mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-11-13 18:03:53 +00:00
Linting fixes
This commit is contained in:
parent
412bbab560
commit
682716dd31
129
.golangci.json
Normal file
129
.golangci.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
110
.golangci.yml
110
.golangci.yml
@ -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
|
|
||||||
@ -6,8 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/common"
|
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
|
|
||||||
|
"github.com/bitechdev/ResolveSpec/pkg/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BunAdapter adapts Bun to work with our Database interface
|
// BunAdapter adapts Bun to work with our Database interface
|
||||||
|
|||||||
@ -5,8 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/common"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"github.com/bitechdev/ResolveSpec/pkg/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GormAdapter adapts GORM to work with our Database interface
|
// GormAdapter adapts GORM to work with our Database interface
|
||||||
|
|||||||
@ -3,8 +3,9 @@ package router
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/common"
|
|
||||||
"github.com/uptrace/bunrouter"
|
"github.com/uptrace/bunrouter"
|
||||||
|
|
||||||
|
"github.com/bitechdev/ResolveSpec/pkg/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BunRouterAdapter adapts uptrace/bunrouter to work with our Router interface
|
// BunRouterAdapter adapts uptrace/bunrouter to work with our Router interface
|
||||||
|
|||||||
@ -5,8 +5,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/common"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"github.com/bitechdev/ResolveSpec/pkg/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MuxAdapter adapts Gorilla Mux to work with our Router interface
|
// MuxAdapter adapts Gorilla Mux to work with our Router interface
|
||||||
|
|||||||
@ -75,7 +75,7 @@ func Debug(template string, args ...interface{}) {
|
|||||||
// CatchPanic - Handle panic
|
// CatchPanic - Handle panic
|
||||||
func CatchPanicCallback(location string, cb func(err any)) {
|
func CatchPanicCallback(location string, cb func(err any)) {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
//callstack := debug.Stack()
|
// callstack := debug.Stack()
|
||||||
|
|
||||||
if Logger != nil {
|
if Logger != nil {
|
||||||
Error("Panic in %s : %v", location, err)
|
Error("Panic in %s : %v", location, err)
|
||||||
@ -84,7 +84,7 @@ func CatchPanicCallback(location string, cb func(err any)) {
|
|||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
//push to sentry
|
// push to sentry
|
||||||
// hub := sentry.CurrentHub()
|
// hub := sentry.CurrentHub()
|
||||||
// if hub != nil {
|
// if hub != nil {
|
||||||
// evtID := hub.Recover(err)
|
// evtID := hub.Recover(err)
|
||||||
|
|||||||
@ -73,11 +73,11 @@ func GetModelColumnDetail(record reflect.Value) []ModelFieldDetail {
|
|||||||
ie := strings.Index(gormdetail[ik:], ";")
|
ie := strings.Index(gormdetail[ik:], ";")
|
||||||
if ie > ik && ik > 0 {
|
if ie > ik && ik > 0 {
|
||||||
fielddetail.SQLName = strings.ToLower(gormdetail)[ik+11 : ik+ie]
|
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)
|
lst = append(lst, fielddetail)
|
||||||
|
|
||||||
|
|||||||
@ -210,7 +210,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
// Apply sorting
|
// Apply sorting
|
||||||
for _, sort := range options.Sort {
|
for _, sort := range options.Sort {
|
||||||
direction := "ASC"
|
direction := "ASC"
|
||||||
if strings.ToLower(sort.Direction) == "desc" {
|
if strings.EqualFold(sort.Direction, "desc") {
|
||||||
direction = "DESC"
|
direction = "DESC"
|
||||||
}
|
}
|
||||||
logger.Debug("Applying sort: %s %s", sort.Column, direction)
|
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) {
|
func (h *Handler) sendResponse(w common.ResponseWriter, data interface{}, metadata *common.Metadata) {
|
||||||
w.SetHeader("Content-Type", "application/json")
|
w.SetHeader("Content-Type", "application/json")
|
||||||
w.WriteJSON(common.Response{
|
err := w.WriteJSON(common.Response{
|
||||||
Success: true,
|
Success: true,
|
||||||
Data: data,
|
Data: data,
|
||||||
Metadata: metadata,
|
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{}) {
|
func (h *Handler) sendError(w common.ResponseWriter, status int, code, message string, details interface{}) {
|
||||||
w.SetHeader("Content-Type", "application/json")
|
w.SetHeader("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
w.WriteJSON(common.Response{
|
err := w.WriteJSON(common.Response{
|
||||||
Success: false,
|
Success: false,
|
||||||
Error: &common.APIError{
|
Error: &common.APIError{
|
||||||
Code: code,
|
Code: code,
|
||||||
@ -988,6 +991,9 @@ func (h *Handler) sendError(w common.ResponseWriter, status int, code, message s
|
|||||||
Detail: fmt.Sprintf("%v", details),
|
Detail: fmt.Sprintf("%v", details),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error sending response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterModel allows registering models at runtime
|
// RegisterModel allows registering models at runtime
|
||||||
|
|||||||
@ -3,13 +3,14 @@ package resolvespec
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"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/gorilla/mux"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
"github.com/uptrace/bunrouter"
|
"github.com/uptrace/bunrouter"
|
||||||
"gorm.io/gorm"
|
"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
|
// NewHandlerWithGORM creates a new Handler with GORM adapter
|
||||||
|
|||||||
@ -140,19 +140,19 @@ func (opts *ExtendedRequestOptions) GetCursorFilter(
|
|||||||
// ------------------------------------------------------------------------- //
|
// ------------------------------------------------------------------------- //
|
||||||
// Helper: get active cursor (forward or backward)
|
// Helper: get active cursor (forward or backward)
|
||||||
func (opts *ExtendedRequestOptions) getActiveCursor() (id string, direction CursorDirection) {
|
func (opts *ExtendedRequestOptions) getActiveCursor() (id string, direction CursorDirection) {
|
||||||
if opts.RequestOptions.CursorForward != "" {
|
if opts.CursorForward != "" {
|
||||||
return opts.RequestOptions.CursorForward, CursorForward
|
return opts.CursorForward, CursorForward
|
||||||
}
|
}
|
||||||
if opts.RequestOptions.CursorBackward != "" {
|
if opts.CursorBackward != "" {
|
||||||
return opts.RequestOptions.CursorBackward, CursorBackward
|
return opts.CursorBackward, CursorBackward
|
||||||
}
|
}
|
||||||
return "", 0
|
return "", 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: extract sort columns
|
// Helper: extract sort columns
|
||||||
func (opts *ExtendedRequestOptions) getSortColumns() []common.SortOption {
|
func (opts *ExtendedRequestOptions) getSortColumns() []common.SortOption {
|
||||||
if opts.RequestOptions.Sort != nil {
|
if opts.Sort != nil {
|
||||||
return opts.RequestOptions.Sort
|
return opts.Sort
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -318,7 +318,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
// Apply sorting
|
// Apply sorting
|
||||||
for _, sort := range options.Sort {
|
for _, sort := range options.Sort {
|
||||||
direction := "ASC"
|
direction := "ASC"
|
||||||
if strings.ToLower(sort.Direction) == "desc" {
|
if strings.EqualFold(sort.Direction, "desc") {
|
||||||
direction = "DESC"
|
direction = "DESC"
|
||||||
}
|
}
|
||||||
logger.Debug("Applying sort: %s %s", sort.Column, direction)
|
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
|
// 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")
|
logger.Debug("Applying cursor pagination")
|
||||||
|
|
||||||
// Get primary key name
|
// 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
|
// 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)
|
pkName := reflection.GetPrimaryKeyName(model)
|
||||||
pkValue := *options.RequestOptions.FetchRowNumber
|
pkValue := *options.FetchRowNumber
|
||||||
|
|
||||||
logger.Debug("Fetching row number for specific PK %s = %s", pkName, pkValue)
|
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))
|
sortParts := make([]string, 0, len(options.Sort))
|
||||||
for _, sort := range options.Sort {
|
for _, sort := range options.Sort {
|
||||||
direction := "ASC"
|
direction := "ASC"
|
||||||
if strings.ToLower(sort.Direction) == "desc" {
|
if strings.EqualFold(sort.Direction, "desc") {
|
||||||
direction = "DESC"
|
direction = "DESC"
|
||||||
}
|
}
|
||||||
sortParts = append(sortParts, fmt.Sprintf("%s.%s %s", tableName, sort.Column, direction))
|
sortParts = append(sortParts, fmt.Sprintf("%s.%s %s", tableName, sort.Column, direction))
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package restheadspec
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -59,7 +58,7 @@ func decodeHeaderValue(value string) string {
|
|||||||
|
|
||||||
// DecodeParam - Decodes parameter string and returns unencoded string
|
// DecodeParam - Decodes parameter string and returns unencoded string
|
||||||
func DecodeParam(pStr string) (string, error) {
|
func DecodeParam(pStr string) (string, error) {
|
||||||
var code string = pStr
|
var code = pStr
|
||||||
if strings.HasPrefix(pStr, "ZIP_") {
|
if strings.HasPrefix(pStr, "ZIP_") {
|
||||||
code = strings.ReplaceAll(pStr, "ZIP_", "")
|
code = strings.ReplaceAll(pStr, "ZIP_", "")
|
||||||
code = strings.ReplaceAll(code, "\n", "")
|
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"):
|
case strings.HasPrefix(normalizedKey, "x-not-select-fields"):
|
||||||
h.parseNotSelectFields(&options, decodedValue)
|
h.parseNotSelectFields(&options, decodedValue)
|
||||||
case strings.HasPrefix(normalizedKey, "x-clean-json"):
|
case strings.HasPrefix(normalizedKey, "x-clean-json"):
|
||||||
options.CleanJSON = strings.ToLower(decodedValue) == "true"
|
options.CleanJSON = strings.EqualFold(decodedValue, "true")
|
||||||
|
|
||||||
// Filtering & Search
|
// Filtering & Search
|
||||||
case strings.HasPrefix(normalizedKey, "x-fieldfilter-"):
|
case strings.HasPrefix(normalizedKey, "x-fieldfilter-"):
|
||||||
@ -166,9 +165,9 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio
|
|||||||
options.Offset = &offset
|
options.Offset = &offset
|
||||||
}
|
}
|
||||||
case strings.HasPrefix(normalizedKey, "x-cursor-forward"):
|
case strings.HasPrefix(normalizedKey, "x-cursor-forward"):
|
||||||
options.RequestOptions.CursorForward = decodedValue
|
options.CursorForward = decodedValue
|
||||||
case strings.HasPrefix(normalizedKey, "x-cursor-backward"):
|
case strings.HasPrefix(normalizedKey, "x-cursor-backward"):
|
||||||
options.RequestOptions.CursorBackward = decodedValue
|
options.CursorBackward = decodedValue
|
||||||
|
|
||||||
// Advanced Features
|
// Advanced Features
|
||||||
case strings.HasPrefix(normalizedKey, "x-advsql-"):
|
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-")
|
colName := strings.TrimPrefix(normalizedKey, "x-cql-sel-")
|
||||||
options.ComputedQL[colName] = decodedValue
|
options.ComputedQL[colName] = decodedValue
|
||||||
case strings.HasPrefix(normalizedKey, "x-distinct"):
|
case strings.HasPrefix(normalizedKey, "x-distinct"):
|
||||||
options.Distinct = strings.ToLower(decodedValue) == "true"
|
options.Distinct = strings.EqualFold(decodedValue, "true")
|
||||||
case strings.HasPrefix(normalizedKey, "x-skipcount"):
|
case strings.HasPrefix(normalizedKey, "x-skipcount"):
|
||||||
options.SkipCount = strings.ToLower(decodedValue) == "true"
|
options.SkipCount = strings.EqualFold(decodedValue, "true")
|
||||||
case strings.HasPrefix(normalizedKey, "x-skipcache"):
|
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"):
|
case strings.HasPrefix(normalizedKey, "x-fetch-rownumber"):
|
||||||
options.RequestOptions.FetchRowNumber = &decodedValue
|
options.FetchRowNumber = &decodedValue
|
||||||
case strings.HasPrefix(normalizedKey, "x-pkrow"):
|
case strings.HasPrefix(normalizedKey, "x-pkrow"):
|
||||||
options.PKRow = &decodedValue
|
options.PKRow = &decodedValue
|
||||||
|
|
||||||
@ -198,7 +197,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio
|
|||||||
|
|
||||||
// Transaction Control
|
// Transaction Control
|
||||||
case strings.HasPrefix(normalizedKey, "x-transaction-atomic"):
|
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
|
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
|
// getColumnTypeFromModel uses reflection to determine the Go type of a column in a model
|
||||||
func (h *Handler) getColumnTypeFromModel(model interface{}, colName string) reflect.Kind {
|
func (h *Handler) getColumnTypeFromModel(model interface{}, colName string) reflect.Kind {
|
||||||
if model == nil {
|
if model == nil {
|
||||||
@ -536,11 +525,6 @@ func isStringType(kind reflect.Kind) bool {
|
|||||||
return kind == reflect.String
|
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
|
// convertToNumericType converts a string value to the appropriate numeric type
|
||||||
func convertToNumericType(value string, kind reflect.Kind) (interface{}, error) {
|
func convertToNumericType(value string, kind reflect.Kind) (interface{}, error) {
|
||||||
value = strings.TrimSpace(value)
|
value = strings.TrimSpace(value)
|
||||||
|
|||||||
@ -95,7 +95,7 @@ func (r *HookRegistry) RegisterMultiple(hookTypes []HookType, hook HookFunc) {
|
|||||||
func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error {
|
func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error {
|
||||||
hooks, exists := r.hooks[hookType]
|
hooks, exists := r.hooks[hookType]
|
||||||
if !exists || len(hooks) == 0 {
|
if !exists || len(hooks) == 0 {
|
||||||
//logger.Debug("No hooks registered for %s", hookType)
|
// logger.Debug("No hooks registered for %s", hookType)
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,13 +55,14 @@ package restheadspec
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"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/gorilla/mux"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
"github.com/uptrace/bunrouter"
|
"github.com/uptrace/bunrouter"
|
||||||
"gorm.io/gorm"
|
"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
|
// NewHandlerWithGORM creates a new Handler with GORM adapter
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
// DBM "github.com/bitechdev/GoCore/pkg/models"
|
||||||
DBM "github.com/bitechdev/GoCore/pkg/models"
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file provides example implementations of the required security callbacks.
|
// 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) {
|
func ExampleLoadColumnSecurityFromDatabase(pUserID int, pSchema, pTablename string) ([]ColumnSecurity, error) {
|
||||||
colSecList := make([]ColumnSecurity, 0)
|
colSecList := make([]ColumnSecurity, 0)
|
||||||
|
|
||||||
getExtraFilters := func(pStr string) map[string]string {
|
// getExtraFilters := func(pStr string) map[string]string {
|
||||||
mp := make(map[string]string, 0)
|
// mp := make(map[string]string, 0)
|
||||||
for i, val := range strings.Split(pStr, ",") {
|
// for i, val := range strings.Split(pStr, ",") {
|
||||||
if i <= 1 {
|
// if i <= 1 {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
vals := strings.Split(val, ":")
|
// vals := strings.Split(val, ":")
|
||||||
if len(vals) > 1 {
|
// if len(vals) > 1 {
|
||||||
mp[vals[0]] = vals[1]
|
// mp[vals[0]] = vals[1]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return mp
|
// return mp
|
||||||
}
|
// }
|
||||||
|
|
||||||
rows, err := DBM.DBConn.Raw(fmt.Sprintf(`
|
// rows, err := DBM.DBConn.Raw(fmt.Sprintf(`
|
||||||
SELECT a.rid_secacces, a.control, a.accesstype, a.jsonvalue
|
// SELECT a.rid_secacces, a.control, a.accesstype, a.jsonvalue
|
||||||
FROM core.secacces a
|
// FROM core.secacces a
|
||||||
WHERE a.rid_hub IN (
|
// WHERE a.rid_hub IN (
|
||||||
SELECT l.rid_hub_parent
|
// SELECT l.rid_hub_parent
|
||||||
FROM core.hub_link l
|
// FROM core.hub_link l
|
||||||
WHERE l.parent_hubtype = 'secgroup'
|
// WHERE l.parent_hubtype = 'secgroup'
|
||||||
AND l.rid_hub_child = ?
|
// AND l.rid_hub_child = ?
|
||||||
)
|
// )
|
||||||
AND control ILIKE '%s.%s%%'
|
// AND control ILIKE '%s.%s%%'
|
||||||
`, pSchema, pTablename), pUserID).Rows()
|
// `, pSchema, pTablename), pUserID).Rows()
|
||||||
|
|
||||||
defer func() {
|
// defer func() {
|
||||||
if rows != nil {
|
// if rows != nil {
|
||||||
rows.Close()
|
// rows.Close()
|
||||||
}
|
// }
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return colSecList, fmt.Errorf("failed to fetch column security from SQL: %v", err)
|
// return colSecList, fmt.Errorf("failed to fetch column security from SQL: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
for rows.Next() {
|
// for rows.Next() {
|
||||||
var rid int
|
// var rid int
|
||||||
var jsondata []byte
|
// var jsondata []byte
|
||||||
var control, accesstype string
|
// var control, accesstype string
|
||||||
|
|
||||||
err = rows.Scan(&rid, &control, &accesstype, &jsondata)
|
// err = rows.Scan(&rid, &control, &accesstype, &jsondata)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return colSecList, fmt.Errorf("failed to scan column security: %v", err)
|
// return colSecList, fmt.Errorf("failed to scan column security: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
parts := strings.Split(control, ",")
|
// parts := strings.Split(control, ",")
|
||||||
ids := strings.Split(parts[0], ".")
|
// ids := strings.Split(parts[0], ".")
|
||||||
if len(ids) < 3 {
|
// if len(ids) < 3 {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
|
|
||||||
jsonvalue := make(map[string]interface{})
|
// jsonvalue := make(map[string]interface{})
|
||||||
if len(jsondata) > 1 {
|
// if len(jsondata) > 1 {
|
||||||
err = json.Unmarshal(jsondata, &jsonvalue)
|
// err = json.Unmarshal(jsondata, &jsonvalue)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
logger.Error("Failed to parse json: %v", err)
|
// logger.Error("Failed to parse json: %v", err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
colsec := ColumnSecurity{
|
// colsec := ColumnSecurity{
|
||||||
Schema: pSchema,
|
// Schema: pSchema,
|
||||||
Tablename: pTablename,
|
// Tablename: pTablename,
|
||||||
UserID: pUserID,
|
// UserID: pUserID,
|
||||||
Path: ids[2:],
|
// Path: ids[2:],
|
||||||
ExtraFilters: getExtraFilters(control),
|
// ExtraFilters: getExtraFilters(control),
|
||||||
Accesstype: accesstype,
|
// Accesstype: accesstype,
|
||||||
Control: control,
|
// Control: control,
|
||||||
ID: int(rid),
|
// ID: int(rid),
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Parse masking configuration from JSON
|
// // Parse masking configuration from JSON
|
||||||
if v, ok := jsonvalue["start"]; ok {
|
// if v, ok := jsonvalue["start"]; ok {
|
||||||
if value, ok := v.(float64); ok {
|
// if value, ok := v.(float64); ok {
|
||||||
colsec.MaskStart = int(value)
|
// colsec.MaskStart = int(value)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, ok := jsonvalue["end"]; ok {
|
// if v, ok := jsonvalue["end"]; ok {
|
||||||
if value, ok := v.(float64); ok {
|
// if value, ok := v.(float64); ok {
|
||||||
colsec.MaskEnd = int(value)
|
// colsec.MaskEnd = int(value)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, ok := jsonvalue["invert"]; ok {
|
// if v, ok := jsonvalue["invert"]; ok {
|
||||||
if value, ok := v.(bool); ok {
|
// if value, ok := v.(bool); ok {
|
||||||
colsec.MaskInvert = value
|
// colsec.MaskInvert = value
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, ok := jsonvalue["char"]; ok {
|
// if v, ok := jsonvalue["char"]; ok {
|
||||||
if value, ok := v.(string); ok {
|
// if value, ok := v.(string); ok {
|
||||||
colsec.MaskChar = value
|
// colsec.MaskChar = value
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
colSecList = append(colSecList, colsec)
|
// colSecList = append(colSecList, colsec)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return colSecList, nil
|
return colSecList, nil
|
||||||
}
|
}
|
||||||
@ -296,34 +293,34 @@ func ExampleLoadRowSecurityFromDatabase(pUserID int, pSchema, pTablename string)
|
|||||||
UserID: pUserID,
|
UserID: pUserID,
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := DBM.DBConn.Raw(`
|
// rows, err := DBM.DBConn.Raw(`
|
||||||
SELECT r.p_retval, r.p_errmsg, r.p_template, r.p_block
|
// SELECT r.p_retval, r.p_errmsg, r.p_template, r.p_block
|
||||||
FROM core.api_sec_rowtemplate(?, ?, ?) r
|
// FROM core.api_sec_rowtemplate(?, ?, ?) r
|
||||||
`, pSchema, pTablename, pUserID).Rows()
|
// `, pSchema, pTablename, pUserID).Rows()
|
||||||
|
|
||||||
defer func() {
|
// defer func() {
|
||||||
if rows != nil {
|
// if rows != nil {
|
||||||
rows.Close()
|
// rows.Close()
|
||||||
}
|
// }
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return record, fmt.Errorf("failed to fetch row security from SQL: %v", err)
|
// return record, fmt.Errorf("failed to fetch row security from SQL: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
for rows.Next() {
|
// for rows.Next() {
|
||||||
var retval int
|
// var retval int
|
||||||
var errmsg string
|
// var errmsg string
|
||||||
|
|
||||||
err = rows.Scan(&retval, &errmsg, &record.Template, &record.HasBlock)
|
// err = rows.Scan(&retval, &errmsg, &record.Template, &record.HasBlock)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return record, fmt.Errorf("failed to scan row security: %v", err)
|
// return record, fmt.Errorf("failed to scan row security: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if retval != 0 {
|
// if retval != 0 {
|
||||||
return RowSecurity{}, fmt.Errorf("api_sec_rowtemplate error: %s", errmsg)
|
// return RowSecurity{}, fmt.Errorf("api_sec_rowtemplate error: %s", errmsg)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return record, nil
|
return record, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Context keys for user information
|
// Context keys for user information
|
||||||
UserIDKey = "user_id"
|
UserIDKey = "user_id"
|
||||||
UserRolesKey = "user_roles"
|
UserRolesKey = "user_roles"
|
||||||
UserTokenKey = "user_token"
|
UserTokenKey = "user_token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthMiddleware extracts user authentication from request and adds to context
|
// AuthMiddleware extracts user authentication from request and adds to context
|
||||||
|
|||||||
@ -146,7 +146,7 @@ func (m *SecurityList) ColumSecurityApplyOnRecord(prevRecord reflect.Value, newR
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, colsec := range colsecList {
|
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
|
continue
|
||||||
}
|
}
|
||||||
lastRecords := interateStruct(prevRecord)
|
lastRecords := interateStruct(prevRecord)
|
||||||
@ -316,7 +316,7 @@ func (m *SecurityList) ApplyColumnSecurity(records reflect.Value, modelType refl
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, colsec := range colsecList {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ func (m *SecurityList) ClearSecurity(pUserID int, pSchema, pTablename string) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, cs := range list {
|
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)
|
filtered = append(filtered, cs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/bitechdev/ResolveSpec/pkg/restheadspec"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"github.com/bitechdev/ResolveSpec/pkg/restheadspec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetupSecurityProvider initializes and configures the security provider
|
// SetupSecurityProvider initializes and configures the security provider
|
||||||
@ -31,7 +32,6 @@ import (
|
|||||||
// // Step 3: Apply middleware
|
// // Step 3: Apply middleware
|
||||||
// router.Use(mux.MiddlewareFunc(security.AuthMiddleware))
|
// router.Use(mux.MiddlewareFunc(security.AuthMiddleware))
|
||||||
// router.Use(mux.MiddlewareFunc(security.SetSecurityMiddleware))
|
// router.Use(mux.MiddlewareFunc(security.SetSecurityMiddleware))
|
||||||
//
|
|
||||||
func SetupSecurityProvider(handler *restheadspec.Handler, securityList *SecurityList) error {
|
func SetupSecurityProvider(handler *restheadspec.Handler, securityList *SecurityList) error {
|
||||||
// Validate that required callbacks are configured
|
// Validate that required callbacks are configured
|
||||||
if securityList.AuthenticateCallback == nil {
|
if securityList.AuthenticateCallback == nil {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user