diff --git a/.golangci.json b/.golangci.json new file mode 100644 index 0000000..28b34d9 --- /dev/null +++ b/.golangci.json @@ -0,0 +1,129 @@ +{ + "formatters": { + "enable": [ + "gofmt", + "goimports" + ], + "exclusions": { + "generated": "lax", + "paths": [ + "third_party$", + "builtin$", + "examples$" + ] + }, + "settings": { + "gofmt": { + "simplify": true + }, + "goimports": { + "local-prefixes": [ + "github.com/bitechdev/ResolveSpec" + ] + } + } + }, + "issues": { + "max-issues-per-linter": 0, + "max-same-issues": 0 + }, + "linters": { + "enable": [ + "gocritic", + "misspell", + "revive" + ], + "exclusions": { + "generated": "lax", + "paths": [ + "third_party$", + "builtin$", + "examples$", + "mocks?", + "tests?" + ], + "rules": [ + { + "linters": [ + "dupl", + "errcheck", + "gocritic", + "gosec" + ], + "path": "_test\\.go" + }, + { + "linters": [ + "errcheck" + ], + "text": "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked" + }, + { + "path": "_test\\.go", + "text": "cognitive complexity|cyclomatic complexity" + } + ] + }, + "settings": { + "errcheck": { + "check-blank": false, + "check-type-assertions": false + }, + "gocritic": { + "enabled-checks": [ + "appendAssign", + "assignOp", + "boolExprSimplify", + "builtinShadow", + "captLocal", + "caseOrder", + "defaultCaseOrder", + "dupArg", + "dupBranchBody", + "dupCase", + "dupSubExpr", + "elseif", + "emptyFallthrough", + "equalFold", + "flagName", + "ifElseChain", + "indexAlloc", + "initClause", + "methodExprCall", + "nilValReturn", + "rangeExprCopy", + "rangeValCopy", + "regexpMust", + "singleCaseSwitch", + "sloppyLen", + "stringXbytes", + "switchTrue", + "typeAssertChain", + "typeSwitchVar", + "underef", + "unlabelStmt", + "unnamedResult", + "unnecessaryBlock", + "weakCond", + "yodaStyleExpr" + ] + }, + "revive": { + "rules": [ + { + "disabled": true, + "name": "exported" + }, + { + "disabled": true, + "name": "package-comments" + } + ] + } + } + }, + "run": { + "tests": true + }, + "version": "2" +} \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index d9266b8..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,110 +0,0 @@ -run: - timeout: 5m - tests: true - skip-dirs: - - vendor - - .github - -linters: - enable: - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - unused - - gofmt - - goimports - - misspell - - gocritic - - revive - - stylecheck - disable: - - typecheck # Can cause issues with generics in some cases - -linters-settings: - errcheck: - check-type-assertions: false - check-blank: false - - govet: - check-shadowing: false - - gofmt: - simplify: true - - goimports: - local-prefixes: github.com/bitechdev/ResolveSpec - - gocritic: - enabled-checks: - - appendAssign - - assignOp - - boolExprSimplify - - builtinShadow - - captLocal - - caseOrder - - defaultCaseOrder - - dupArg - - dupBranchBody - - dupCase - - dupSubExpr - - elseif - - emptyFallthrough - - equalFold - - flagName - - ifElseChain - - indexAlloc - - initClause - - methodExprCall - - nilValReturn - - rangeExprCopy - - rangeValCopy - - regexpMust - - singleCaseSwitch - - sloppyLen - - stringXbytes - - switchTrue - - typeAssertChain - - typeSwitchVar - - underef - - unlabelStmt - - unnamedResult - - unnecessaryBlock - - weakCond - - yodaStyleExpr - - revive: - rules: - - name: exported - disabled: true - - name: package-comments - disabled: true - -issues: - exclude-use-default: false - max-issues-per-linter: 0 - max-same-issues: 0 - - # Exclude some linters from running on tests files - exclude-rules: - - path: _test\.go - linters: - - errcheck - - dupl - - gosec - - gocritic - - # Ignore "error return value not checked" for defer statements - - linters: - - errcheck - text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked" - - # Ignore complexity in test files - - path: _test\.go - text: "cognitive complexity|cyclomatic complexity" - -output: - format: colored-line-number - print-issued-lines: true - print-linter-name: true diff --git a/pkg/common/adapters/database/bun.go b/pkg/common/adapters/database/bun.go index 7494648..2fe04b1 100644 --- a/pkg/common/adapters/database/bun.go +++ b/pkg/common/adapters/database/bun.go @@ -6,8 +6,9 @@ import ( "fmt" "strings" - "github.com/bitechdev/ResolveSpec/pkg/common" "github.com/uptrace/bun" + + "github.com/bitechdev/ResolveSpec/pkg/common" ) // BunAdapter adapts Bun to work with our Database interface diff --git a/pkg/common/adapters/database/gorm.go b/pkg/common/adapters/database/gorm.go index 92a82ac..6372bd8 100644 --- a/pkg/common/adapters/database/gorm.go +++ b/pkg/common/adapters/database/gorm.go @@ -5,8 +5,9 @@ import ( "fmt" "strings" - "github.com/bitechdev/ResolveSpec/pkg/common" "gorm.io/gorm" + + "github.com/bitechdev/ResolveSpec/pkg/common" ) // GormAdapter adapts GORM to work with our Database interface diff --git a/pkg/common/adapters/router/bunrouter.go b/pkg/common/adapters/router/bunrouter.go index 55b8888..c4c1ab6 100644 --- a/pkg/common/adapters/router/bunrouter.go +++ b/pkg/common/adapters/router/bunrouter.go @@ -3,8 +3,9 @@ package router import ( "net/http" - "github.com/bitechdev/ResolveSpec/pkg/common" "github.com/uptrace/bunrouter" + + "github.com/bitechdev/ResolveSpec/pkg/common" ) // BunRouterAdapter adapts uptrace/bunrouter to work with our Router interface diff --git a/pkg/common/adapters/router/mux.go b/pkg/common/adapters/router/mux.go index 405d966..2eb199e 100644 --- a/pkg/common/adapters/router/mux.go +++ b/pkg/common/adapters/router/mux.go @@ -5,8 +5,9 @@ import ( "io" "net/http" - "github.com/bitechdev/ResolveSpec/pkg/common" "github.com/gorilla/mux" + + "github.com/bitechdev/ResolveSpec/pkg/common" ) // MuxAdapter adapts Gorilla Mux to work with our Router interface diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index ba8e4e1..c4767ea 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -75,7 +75,7 @@ func Debug(template string, args ...interface{}) { // CatchPanic - Handle panic func CatchPanicCallback(location string, cb func(err any)) { if err := recover(); err != nil { - //callstack := debug.Stack() + // callstack := debug.Stack() if Logger != nil { Error("Panic in %s : %v", location, err) @@ -84,7 +84,7 @@ func CatchPanicCallback(location string, cb func(err any)) { debug.PrintStack() } - //push to sentry + // push to sentry // hub := sentry.CurrentHub() // if hub != nil { // evtID := hub.Recover(err) diff --git a/pkg/modelregistry/model_registry.go b/pkg/modelregistry/model_registry.go index 8f98084..01b5e19 100644 --- a/pkg/modelregistry/model_registry.go +++ b/pkg/modelregistry/model_registry.go @@ -69,19 +69,19 @@ func (r *DefaultModelRegistry) RegisterModel(name string, model interface{}) err func (r *DefaultModelRegistry) GetModel(name string) (interface{}, error) { r.mutex.RLock() defer r.mutex.RUnlock() - + model, exists := r.models[name] if !exists { return nil, fmt.Errorf("model %s not found", name) } - + return model, nil } func (r *DefaultModelRegistry) GetAllModels() map[string]interface{} { r.mutex.RLock() defer r.mutex.RUnlock() - + result := make(map[string]interface{}) for k, v := range r.models { result[k] = v @@ -132,4 +132,4 @@ func GetModels() []interface{} { models = append(models, model) } return models -} \ No newline at end of file +} diff --git a/pkg/reflection/generic_model.go b/pkg/reflection/generic_model.go index 1463958..010adf9 100644 --- a/pkg/reflection/generic_model.go +++ b/pkg/reflection/generic_model.go @@ -73,11 +73,11 @@ func GetModelColumnDetail(record reflect.Value) []ModelFieldDetail { ie := strings.Index(gormdetail[ik:], ";") if ie > ik && ik > 0 { fielddetail.SQLName = strings.ToLower(gormdetail)[ik+11 : ik+ie] - //fmt.Printf("\r\nforeignkey: %v", fielddetail) + // fmt.Printf("\r\nforeignkey: %v", fielddetail) } } - //";foreignkey:rid_parent;association_foreignkey:id_atevent;save_associations:false;association_autocreate:false;" + // ";foreignkey:rid_parent;association_foreignkey:id_atevent;save_associations:false;association_autocreate:false;" lst = append(lst, fielddetail) diff --git a/pkg/resolvespec/handler.go b/pkg/resolvespec/handler.go index 09e03eb..c0ef4b5 100644 --- a/pkg/resolvespec/handler.go +++ b/pkg/resolvespec/handler.go @@ -210,7 +210,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st // Apply sorting for _, sort := range options.Sort { direction := "ASC" - if strings.ToLower(sort.Direction) == "desc" { + if strings.EqualFold(sort.Direction, "desc") { direction = "DESC" } logger.Debug("Applying sort: %s %s", sort.Column, direction) @@ -969,17 +969,20 @@ func (h *Handler) generateMetadata(schema, entity string, model interface{}) *co func (h *Handler) sendResponse(w common.ResponseWriter, data interface{}, metadata *common.Metadata) { w.SetHeader("Content-Type", "application/json") - w.WriteJSON(common.Response{ + err := w.WriteJSON(common.Response{ Success: true, Data: data, Metadata: metadata, }) + if err != nil { + logger.Error("Error sending response: %v", err) + } } func (h *Handler) sendError(w common.ResponseWriter, status int, code, message string, details interface{}) { w.SetHeader("Content-Type", "application/json") w.WriteHeader(status) - w.WriteJSON(common.Response{ + err := w.WriteJSON(common.Response{ Success: false, Error: &common.APIError{ Code: code, @@ -988,6 +991,9 @@ func (h *Handler) sendError(w common.ResponseWriter, status int, code, message s Detail: fmt.Sprintf("%v", details), }, }) + if err != nil { + logger.Error("Error sending response: %v", err) + } } // RegisterModel allows registering models at runtime diff --git a/pkg/resolvespec/interfaces.go b/pkg/resolvespec/interfaces.go index 9e25c7f..16cf4a4 100644 --- a/pkg/resolvespec/interfaces.go +++ b/pkg/resolvespec/interfaces.go @@ -23,5 +23,5 @@ func (r GormTableCRUDRequest) GetRequest() string { // New interfaces that replace the legacy ones above // These are now defined in database.go: -// - TableNameProvider (replaces GormTableNameInterface) +// - TableNameProvider (replaces GormTableNameInterface) // - SchemaProvider (replaces GormTableSchemaInterface) diff --git a/pkg/resolvespec/resolvespec.go b/pkg/resolvespec/resolvespec.go index 980bcc1..dbbd11c 100644 --- a/pkg/resolvespec/resolvespec.go +++ b/pkg/resolvespec/resolvespec.go @@ -3,13 +3,14 @@ package resolvespec import ( "net/http" - "github.com/bitechdev/ResolveSpec/pkg/common/adapters/database" - "github.com/bitechdev/ResolveSpec/pkg/common/adapters/router" - "github.com/bitechdev/ResolveSpec/pkg/modelregistry" "github.com/gorilla/mux" "github.com/uptrace/bun" "github.com/uptrace/bunrouter" "gorm.io/gorm" + + "github.com/bitechdev/ResolveSpec/pkg/common/adapters/database" + "github.com/bitechdev/ResolveSpec/pkg/common/adapters/router" + "github.com/bitechdev/ResolveSpec/pkg/modelregistry" ) // NewHandlerWithGORM creates a new Handler with GORM adapter diff --git a/pkg/restheadspec/cursor.go b/pkg/restheadspec/cursor.go index ba78436..dd31607 100644 --- a/pkg/restheadspec/cursor.go +++ b/pkg/restheadspec/cursor.go @@ -140,19 +140,19 @@ func (opts *ExtendedRequestOptions) GetCursorFilter( // ------------------------------------------------------------------------- // // Helper: get active cursor (forward or backward) func (opts *ExtendedRequestOptions) getActiveCursor() (id string, direction CursorDirection) { - if opts.RequestOptions.CursorForward != "" { - return opts.RequestOptions.CursorForward, CursorForward + if opts.CursorForward != "" { + return opts.CursorForward, CursorForward } - if opts.RequestOptions.CursorBackward != "" { - return opts.RequestOptions.CursorBackward, CursorBackward + if opts.CursorBackward != "" { + return opts.CursorBackward, CursorBackward } return "", 0 } // Helper: extract sort columns func (opts *ExtendedRequestOptions) getSortColumns() []common.SortOption { - if opts.RequestOptions.Sort != nil { - return opts.RequestOptions.Sort + if opts.Sort != nil { + return opts.Sort } return nil } diff --git a/pkg/restheadspec/handler.go b/pkg/restheadspec/handler.go index 183fa7e..979027d 100644 --- a/pkg/restheadspec/handler.go +++ b/pkg/restheadspec/handler.go @@ -318,7 +318,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st // Apply sorting for _, sort := range options.Sort { direction := "ASC" - if strings.ToLower(sort.Direction) == "desc" { + if strings.EqualFold(sort.Direction, "desc") { direction = "DESC" } logger.Debug("Applying sort: %s %s", sort.Column, direction) @@ -352,7 +352,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st } // Apply cursor-based pagination - if len(options.RequestOptions.CursorForward) > 0 || len(options.RequestOptions.CursorBackward) > 0 { + if len(options.CursorForward) > 0 || len(options.CursorBackward) > 0 { logger.Debug("Applying cursor pagination") // Get primary key name @@ -425,9 +425,9 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st } // Fetch row number for a specific record if requested - if options.RequestOptions.FetchRowNumber != nil && *options.RequestOptions.FetchRowNumber != "" { + if options.FetchRowNumber != nil && *options.FetchRowNumber != "" { pkName := reflection.GetPrimaryKeyName(model) - pkValue := *options.RequestOptions.FetchRowNumber + pkValue := *options.FetchRowNumber logger.Debug("Fetching row number for specific PK %s = %s", pkName, pkValue) @@ -1415,7 +1415,7 @@ func (h *Handler) FetchRowNumber(ctx context.Context, tableName string, pkName s sortParts := make([]string, 0, len(options.Sort)) for _, sort := range options.Sort { direction := "ASC" - if strings.ToLower(sort.Direction) == "desc" { + if strings.EqualFold(sort.Direction, "desc") { direction = "DESC" } sortParts = append(sortParts, fmt.Sprintf("%s.%s %s", tableName, sort.Column, direction)) diff --git a/pkg/restheadspec/headers.go b/pkg/restheadspec/headers.go index bc2e6a3..31d426e 100644 --- a/pkg/restheadspec/headers.go +++ b/pkg/restheadspec/headers.go @@ -2,7 +2,6 @@ package restheadspec import ( "encoding/base64" - "encoding/json" "fmt" "reflect" "strconv" @@ -59,7 +58,7 @@ func decodeHeaderValue(value string) string { // DecodeParam - Decodes parameter string and returns unencoded string func DecodeParam(pStr string) (string, error) { - var code string = pStr + var code = pStr if strings.HasPrefix(pStr, "ZIP_") { code = strings.ReplaceAll(pStr, "ZIP_", "") code = strings.ReplaceAll(code, "\n", "") @@ -125,7 +124,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio case strings.HasPrefix(normalizedKey, "x-not-select-fields"): h.parseNotSelectFields(&options, decodedValue) case strings.HasPrefix(normalizedKey, "x-clean-json"): - options.CleanJSON = strings.ToLower(decodedValue) == "true" + options.CleanJSON = strings.EqualFold(decodedValue, "true") // Filtering & Search case strings.HasPrefix(normalizedKey, "x-fieldfilter-"): @@ -166,9 +165,9 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio options.Offset = &offset } case strings.HasPrefix(normalizedKey, "x-cursor-forward"): - options.RequestOptions.CursorForward = decodedValue + options.CursorForward = decodedValue case strings.HasPrefix(normalizedKey, "x-cursor-backward"): - options.RequestOptions.CursorBackward = decodedValue + options.CursorBackward = decodedValue // Advanced Features case strings.HasPrefix(normalizedKey, "x-advsql-"): @@ -178,13 +177,13 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio colName := strings.TrimPrefix(normalizedKey, "x-cql-sel-") options.ComputedQL[colName] = decodedValue case strings.HasPrefix(normalizedKey, "x-distinct"): - options.Distinct = strings.ToLower(decodedValue) == "true" + options.Distinct = strings.EqualFold(decodedValue, "true") case strings.HasPrefix(normalizedKey, "x-skipcount"): - options.SkipCount = strings.ToLower(decodedValue) == "true" + options.SkipCount = strings.EqualFold(decodedValue, "true") case strings.HasPrefix(normalizedKey, "x-skipcache"): - options.SkipCache = strings.ToLower(decodedValue) == "true" + options.SkipCache = strings.EqualFold(decodedValue, "true") case strings.HasPrefix(normalizedKey, "x-fetch-rownumber"): - options.RequestOptions.FetchRowNumber = &decodedValue + options.FetchRowNumber = &decodedValue case strings.HasPrefix(normalizedKey, "x-pkrow"): options.PKRow = &decodedValue @@ -198,7 +197,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio // Transaction Control case strings.HasPrefix(normalizedKey, "x-transaction-atomic"): - options.AtomicTransaction = strings.ToLower(decodedValue) == "true" + options.AtomicTransaction = strings.EqualFold(decodedValue, "true") } } @@ -455,16 +454,6 @@ func (h *Handler) parseCommaSeparated(value string) []string { return result } -// parseJSONHeader parses a header value as JSON -func (h *Handler) parseJSONHeader(value string) (map[string]interface{}, error) { - var result map[string]interface{} - err := json.Unmarshal([]byte(value), &result) - if err != nil { - return nil, fmt.Errorf("failed to parse JSON header: %w", err) - } - return result, nil -} - // getColumnTypeFromModel uses reflection to determine the Go type of a column in a model func (h *Handler) getColumnTypeFromModel(model interface{}, colName string) reflect.Kind { if model == nil { @@ -536,11 +525,6 @@ func isStringType(kind reflect.Kind) bool { return kind == reflect.String } -// isBoolType checks if a reflect.Kind is a boolean type -func isBoolType(kind reflect.Kind) bool { - return kind == reflect.Bool -} - // convertToNumericType converts a string value to the appropriate numeric type func convertToNumericType(value string, kind reflect.Kind) (interface{}, error) { value = strings.TrimSpace(value) diff --git a/pkg/restheadspec/hooks.go b/pkg/restheadspec/hooks.go index cab8c2d..788fd2f 100644 --- a/pkg/restheadspec/hooks.go +++ b/pkg/restheadspec/hooks.go @@ -95,7 +95,7 @@ func (r *HookRegistry) RegisterMultiple(hookTypes []HookType, hook HookFunc) { func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error { hooks, exists := r.hooks[hookType] if !exists || len(hooks) == 0 { - //logger.Debug("No hooks registered for %s", hookType) + // logger.Debug("No hooks registered for %s", hookType) return nil } @@ -108,7 +108,7 @@ func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error { } } - //logger.Debug("All hooks for %s executed successfully", hookType) + // logger.Debug("All hooks for %s executed successfully", hookType) return nil } diff --git a/pkg/restheadspec/restheadspec.go b/pkg/restheadspec/restheadspec.go index a471a40..e34d200 100644 --- a/pkg/restheadspec/restheadspec.go +++ b/pkg/restheadspec/restheadspec.go @@ -55,13 +55,14 @@ package restheadspec import ( "net/http" - "github.com/bitechdev/ResolveSpec/pkg/common/adapters/database" - "github.com/bitechdev/ResolveSpec/pkg/common/adapters/router" - "github.com/bitechdev/ResolveSpec/pkg/modelregistry" "github.com/gorilla/mux" "github.com/uptrace/bun" "github.com/uptrace/bunrouter" "gorm.io/gorm" + + "github.com/bitechdev/ResolveSpec/pkg/common/adapters/database" + "github.com/bitechdev/ResolveSpec/pkg/common/adapters/router" + "github.com/bitechdev/ResolveSpec/pkg/modelregistry" ) // NewHandlerWithGORM creates a new Handler with GORM adapter diff --git a/pkg/security/callbacks_example.go b/pkg/security/callbacks_example.go index 5e0d3ba..5ddd8f9 100644 --- a/pkg/security/callbacks_example.go +++ b/pkg/security/callbacks_example.go @@ -1,14 +1,11 @@ package security import ( - "encoding/json" "fmt" "net/http" "strconv" "strings" - - DBM "github.com/bitechdev/GoCore/pkg/models" - "github.com/bitechdev/ResolveSpec/pkg/logger" + // DBM "github.com/bitechdev/GoCore/pkg/models" ) // This file provides example implementations of the required security callbacks. @@ -121,104 +118,104 @@ func ExampleAuthenticateFromSession(r *http.Request) (userID int, roles string, func ExampleLoadColumnSecurityFromDatabase(pUserID int, pSchema, pTablename string) ([]ColumnSecurity, error) { colSecList := make([]ColumnSecurity, 0) - getExtraFilters := func(pStr string) map[string]string { - mp := make(map[string]string, 0) - for i, val := range strings.Split(pStr, ",") { - if i <= 1 { - continue - } - vals := strings.Split(val, ":") - if len(vals) > 1 { - mp[vals[0]] = vals[1] - } - } - return mp - } + // getExtraFilters := func(pStr string) map[string]string { + // mp := make(map[string]string, 0) + // for i, val := range strings.Split(pStr, ",") { + // if i <= 1 { + // continue + // } + // vals := strings.Split(val, ":") + // if len(vals) > 1 { + // mp[vals[0]] = vals[1] + // } + // } + // return mp + // } - rows, err := DBM.DBConn.Raw(fmt.Sprintf(` - SELECT a.rid_secacces, a.control, a.accesstype, a.jsonvalue - FROM core.secacces a - WHERE a.rid_hub IN ( - SELECT l.rid_hub_parent - FROM core.hub_link l - WHERE l.parent_hubtype = 'secgroup' - AND l.rid_hub_child = ? - ) - AND control ILIKE '%s.%s%%' - `, pSchema, pTablename), pUserID).Rows() + // rows, err := DBM.DBConn.Raw(fmt.Sprintf(` + // SELECT a.rid_secacces, a.control, a.accesstype, a.jsonvalue + // FROM core.secacces a + // WHERE a.rid_hub IN ( + // SELECT l.rid_hub_parent + // FROM core.hub_link l + // WHERE l.parent_hubtype = 'secgroup' + // AND l.rid_hub_child = ? + // ) + // AND control ILIKE '%s.%s%%' + // `, pSchema, pTablename), pUserID).Rows() - defer func() { - if rows != nil { - rows.Close() - } - }() + // defer func() { + // if rows != nil { + // rows.Close() + // } + // }() - if err != nil { - return colSecList, fmt.Errorf("failed to fetch column security from SQL: %v", err) - } + // if err != nil { + // return colSecList, fmt.Errorf("failed to fetch column security from SQL: %v", err) + // } - for rows.Next() { - var rid int - var jsondata []byte - var control, accesstype string + // for rows.Next() { + // var rid int + // var jsondata []byte + // var control, accesstype string - err = rows.Scan(&rid, &control, &accesstype, &jsondata) - if err != nil { - return colSecList, fmt.Errorf("failed to scan column security: %v", err) - } + // err = rows.Scan(&rid, &control, &accesstype, &jsondata) + // if err != nil { + // return colSecList, fmt.Errorf("failed to scan column security: %v", err) + // } - parts := strings.Split(control, ",") - ids := strings.Split(parts[0], ".") - if len(ids) < 3 { - continue - } + // parts := strings.Split(control, ",") + // ids := strings.Split(parts[0], ".") + // if len(ids) < 3 { + // continue + // } - jsonvalue := make(map[string]interface{}) - if len(jsondata) > 1 { - err = json.Unmarshal(jsondata, &jsonvalue) - if err != nil { - logger.Error("Failed to parse json: %v", err) - } - } + // jsonvalue := make(map[string]interface{}) + // if len(jsondata) > 1 { + // err = json.Unmarshal(jsondata, &jsonvalue) + // if err != nil { + // logger.Error("Failed to parse json: %v", err) + // } + // } - colsec := ColumnSecurity{ - Schema: pSchema, - Tablename: pTablename, - UserID: pUserID, - Path: ids[2:], - ExtraFilters: getExtraFilters(control), - Accesstype: accesstype, - Control: control, - ID: int(rid), - } + // colsec := ColumnSecurity{ + // Schema: pSchema, + // Tablename: pTablename, + // UserID: pUserID, + // Path: ids[2:], + // ExtraFilters: getExtraFilters(control), + // Accesstype: accesstype, + // Control: control, + // ID: int(rid), + // } - // Parse masking configuration from JSON - if v, ok := jsonvalue["start"]; ok { - if value, ok := v.(float64); ok { - colsec.MaskStart = int(value) - } - } + // // Parse masking configuration from JSON + // if v, ok := jsonvalue["start"]; ok { + // if value, ok := v.(float64); ok { + // colsec.MaskStart = int(value) + // } + // } - if v, ok := jsonvalue["end"]; ok { - if value, ok := v.(float64); ok { - colsec.MaskEnd = int(value) - } - } + // if v, ok := jsonvalue["end"]; ok { + // if value, ok := v.(float64); ok { + // colsec.MaskEnd = int(value) + // } + // } - if v, ok := jsonvalue["invert"]; ok { - if value, ok := v.(bool); ok { - colsec.MaskInvert = value - } - } + // if v, ok := jsonvalue["invert"]; ok { + // if value, ok := v.(bool); ok { + // colsec.MaskInvert = value + // } + // } - if v, ok := jsonvalue["char"]; ok { - if value, ok := v.(string); ok { - colsec.MaskChar = value - } - } + // if v, ok := jsonvalue["char"]; ok { + // if value, ok := v.(string); ok { + // colsec.MaskChar = value + // } + // } - colSecList = append(colSecList, colsec) - } + // colSecList = append(colSecList, colsec) + // } return colSecList, nil } @@ -296,34 +293,34 @@ func ExampleLoadRowSecurityFromDatabase(pUserID int, pSchema, pTablename string) UserID: pUserID, } - rows, err := DBM.DBConn.Raw(` - SELECT r.p_retval, r.p_errmsg, r.p_template, r.p_block - FROM core.api_sec_rowtemplate(?, ?, ?) r - `, pSchema, pTablename, pUserID).Rows() + // rows, err := DBM.DBConn.Raw(` + // SELECT r.p_retval, r.p_errmsg, r.p_template, r.p_block + // FROM core.api_sec_rowtemplate(?, ?, ?) r + // `, pSchema, pTablename, pUserID).Rows() - defer func() { - if rows != nil { - rows.Close() - } - }() + // defer func() { + // if rows != nil { + // rows.Close() + // } + // }() - if err != nil { - return record, fmt.Errorf("failed to fetch row security from SQL: %v", err) - } + // if err != nil { + // return record, fmt.Errorf("failed to fetch row security from SQL: %v", err) + // } - for rows.Next() { - var retval int - var errmsg string + // for rows.Next() { + // var retval int + // var errmsg string - err = rows.Scan(&retval, &errmsg, &record.Template, &record.HasBlock) - if err != nil { - return record, fmt.Errorf("failed to scan row security: %v", err) - } + // err = rows.Scan(&retval, &errmsg, &record.Template, &record.HasBlock) + // if err != nil { + // return record, fmt.Errorf("failed to scan row security: %v", err) + // } - if retval != 0 { - return RowSecurity{}, fmt.Errorf("api_sec_rowtemplate error: %s", errmsg) - } - } + // if retval != 0 { + // return RowSecurity{}, fmt.Errorf("api_sec_rowtemplate error: %s", errmsg) + // } + // } return record, nil } diff --git a/pkg/security/middleware.go b/pkg/security/middleware.go index b9caa59..7263edd 100644 --- a/pkg/security/middleware.go +++ b/pkg/security/middleware.go @@ -7,9 +7,9 @@ import ( const ( // Context keys for user information - UserIDKey = "user_id" - UserRolesKey = "user_roles" - UserTokenKey = "user_token" + UserIDKey = "user_id" + UserRolesKey = "user_roles" + UserTokenKey = "user_token" ) // AuthMiddleware extracts user authentication from request and adds to context diff --git a/pkg/security/provider.go b/pkg/security/provider.go index d5fabf8..8f4f7d7 100644 --- a/pkg/security/provider.go +++ b/pkg/security/provider.go @@ -146,7 +146,7 @@ func (m *SecurityList) ColumSecurityApplyOnRecord(prevRecord reflect.Value, newR } for _, colsec := range colsecList { - if !(strings.EqualFold(colsec.Accesstype, "mask") || strings.EqualFold(colsec.Accesstype, "hide")) { + if !strings.EqualFold(colsec.Accesstype, "mask") && !strings.EqualFold(colsec.Accesstype, "hide") { continue } lastRecords := interateStruct(prevRecord) @@ -316,7 +316,7 @@ func (m *SecurityList) ApplyColumnSecurity(records reflect.Value, modelType refl } for _, colsec := range colsecList { - if !(strings.EqualFold(colsec.Accesstype, "mask") || strings.EqualFold(colsec.Accesstype, "hide")) { + if !strings.EqualFold(colsec.Accesstype, "mask") && !strings.EqualFold(colsec.Accesstype, "hide") { continue } @@ -408,7 +408,7 @@ func (m *SecurityList) ClearSecurity(pUserID int, pSchema, pTablename string) er } for _, cs := range list { - if !(cs.Schema == pSchema && cs.Tablename == pTablename && cs.UserID == pUserID) { + if cs.Schema != pSchema && cs.Tablename != pTablename && cs.UserID != pUserID { filtered = append(filtered, cs) } } diff --git a/pkg/security/setup_example.go b/pkg/security/setup_example.go index 08cc56d..7300e9d 100644 --- a/pkg/security/setup_example.go +++ b/pkg/security/setup_example.go @@ -4,9 +4,10 @@ import ( "fmt" "net/http" - "github.com/bitechdev/ResolveSpec/pkg/restheadspec" "github.com/gorilla/mux" "gorm.io/gorm" + + "github.com/bitechdev/ResolveSpec/pkg/restheadspec" ) // SetupSecurityProvider initializes and configures the security provider @@ -31,7 +32,6 @@ import ( // // Step 3: Apply middleware // router.Use(mux.MiddlewareFunc(security.AuthMiddleware)) // router.Use(mux.MiddlewareFunc(security.SetSecurityMiddleware)) -// func SetupSecurityProvider(handler *restheadspec.Handler, securityList *SecurityList) error { // Validate that required callbacks are configured if securityList.AuthenticateCallback == nil {