New lint rules

This commit is contained in:
Jamie Curnow 2024-11-21 19:07:36 +10:00
parent 4e6d65645f
commit 152b7666d8
No known key found for this signature in database
GPG Key ID: FFBB624C43388E9E
85 changed files with 385 additions and 259 deletions

View File

@ -1,63 +1,166 @@
---
linters: linters:
enable: enable:
- bodyclose # Prevents against memory leaks in production caused by not closing
- errcheck # file handle
- gosimple - bodyclose
- govet # Detects cloned code. DRY is good programming practice. Can cause issues
- gosec # with testing code where simplicity is preferred over duplication.
- goconst # Disabled for test code.
- gocritic # - dupl
- gocyclo # Detects unchecked errors in go programs. These unchecked errors can be
- gofmt # critical bugs in some cases.
- goimports - errcheck
- ineffassign # Simplifies go code.
- misspell - gosimple
- nakedret # Controls Go package import order and makes it always deterministic.
- prealloc - gci
#- revive # Reports suspicious constructs, maintained by goteam. e.g. Printf unused
- staticcheck # params not caught at compile time.
- typecheck - govet
- unused # Detect security issues with gocode. Use of secrets in code or obsolete
- unconvert # security algorithms. It's imaged heuristic methods are used in finding
- unparam # problems. If issues with rules are found particular rules can be disabled
# as required. Could possibility cause issues with testing.
# Disabled for test code.
- gosec
# Detect repeated strings that could be replaced by a constant
- goconst
# Misc linters missing from other projects. Grouped into 3 categories
# diagnostics, style and performance
- gocritic
# Limits code cyclomatic complexity
- gocyclo
# Detects if code needs to be gofmt'd
- gofmt
# Detects unused go package imports
- goimports
# Detects style mistakes not correctness. Golint is meant to carry out the
# stylistic conventions put forth in Effective Go and CodeReviewComments.
# golint has false positives and false negatives and can be tweaked.
- revive
# Detects ineffectual assignments in code
- ineffassign
# Reports long lines
# - lll
# Detect commonly misspelled english words in comments
- misspell
# Detect naked returns on non-trivial functions, and conform with
# Go CodeReviewComments
- nakedret
# Detect slice allocations that can be preallocated
- prealloc
# Misc collection of static analysis tools
- staticcheck
# Detects unused struct fields
# - structcheck
# Parses and typechecks the code like the go compiler
- typecheck
# Detects unused constants, variables, functions and types
- unused
# Remove unnecessary type conversions
- unconvert
# Remove unnecessary(unused) function parameters
- unparam
linters-settings: linters-settings:
gosec: errcheck:
excludes: exclude-functions:
- G115 - fmt.Fprint
errcheck: - fmt.Fprintf
exclude-functions: gci:
- fmt.Fprint sections:
- fmt.Fprintf - standard # Standard section: captures all standard packages.
goconst: - localmodule # Local module section: contains all local packages.
# minimal length of string constant # - prefix(gogs.jc21.com) # Prefixed gerrit.lan packages (jumgo).
# default: 3 - default # Everything else (github.com, golang.org, etc).
min-len: 2 - blank # Blank section: contains all blank imports.
# minimum number of occurrences of string constant custom-order: true
# default: 3 goconst:
min-occurences: 2 # minimal length of string constant
misspell: # default: 3
locale: UK min-len: 2
ignore-words: # minimum number of occurrences of string constant
- color # default: 3
min-occurences: 2
revive:
enable-all-rules: true
rules:
- name: unchecked-type-assertion
disabled: true
# handled by goconst
- name: add-constant
disabled: true
# cant limit this arbitrarily
- name: argument-limit
disabled: true
# handled by gocyclo
- name: cognitive-complexity
disabled: true
# false positive for Exported vs non-exported functions of the same name
- name: confusing-naming
disabled: true
# false positives for "" - which is the nil value of a string (also 0)
- name: confusing-results
disabled: true
# handled by gocyclo
- name: cyclomatic
disabled: true
# have comments on exported functions but not on vars/types/constants
- name: exported
arguments:
- "disableChecksOnConstants"
- "disableChecksOnTypes"
- "disableChecksOnVariables"
# false positives on bool params
- name: flag-parameter
disabled: true
# extreme verticalization can happen
- name: function-length
disabled: true
# can false positive for non-getters
- name: get-return
disabled: true
# only allows lowercase names
- name: import-alias-naming
disabled: true
# handled by lll
- name: line-length-limit
disabled: true
# don't want to arbitrarily limit this
# many places have specific model.go files to contain all structs
- name: max-public-structs
disabled: true
# disable package-comments
- name: package-comments
disabled: true
# this is handled by errcheck
- name: unhandled-error
disabled: true
- name: function-result-limit
disabled: true
issues: issues:
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3. # Maximum count of issues with the same text. Set to 0 to disable. Default
# We have chosen an arbitrary value that works based on practical usage. # is 3. We have chosen an arbitrary value that works based on practical usage.
max-same: 20 max-same: 20
# See cmdline flag documentation for more info about default excludes --exclude-use-default # See cmdline flag documentation for more info about default excludes
# Nothing is excluded by default # --exclude-use-default. Nothing is excluded by default
exclude-use-default: false exclude-use-default: false
# Excluding configuration per-path, per-linter, per-text and per-source # Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules: exclude-rules:
# Exclude some linters from running on tests files. # TODO: Add examples why this is good # Exclude some linters from running on tests files.
# TODO: Add examples why this is good
- path: _test\.go - path: _test\.go
linters: linters:
# Tests should be simple? Add example why this is good? # Tests should be simple? Add example why this is good?
- gocyclo - gocyclo
# Error checking adds verbosity and complexity for minimal value # Error checking adds verbosity and complexity for minimal value
- errcheck - errcheck
# Table test encourage duplication in defining the table tests. # Table test encourage duplication in defining the table tests.
- dupl - dupl
# Hard coded example tokens, SQL injection and other bad practices may # Hard coded example tokens, SQL injection and other bad practices may
# want to be tested # want to be tested
- gosec - gosec
# Test data can long
# - lll
run:
go: '1.23'

View File

@ -3,17 +3,17 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
h "npm/internal/api/http"
"npm/internal/errors"
"npm/internal/logger"
"slices" "slices"
"time" "time"
c "npm/internal/api/context" c "npm/internal/api/context"
h "npm/internal/api/http"
"npm/internal/entity/auth" "npm/internal/entity/auth"
"npm/internal/entity/setting" "npm/internal/entity/setting"
"npm/internal/entity/user" "npm/internal/entity/user"
"npm/internal/errors"
njwt "npm/internal/jwt" njwt "npm/internal/jwt"
"npm/internal/logger"
"gorm.io/gorm" "gorm.io/gorm"
) )

View File

@ -151,7 +151,7 @@ func getCertificateFromRequest(w http.ResponseWriter, r *http.Request) *certific
// fillObjectFromBody has some reusable code for all endpoints that // fillObjectFromBody has some reusable code for all endpoints that
// have a certificate id in the url. it will write errors to the output. // have a certificate id in the url. it will write errors to the output.
func fillObjectFromBody(w http.ResponseWriter, r *http.Request, validationSchema string, o interface{}) bool { func fillObjectFromBody(w http.ResponseWriter, r *http.Request, validationSchema string, o any) bool {
bodyBytes, _ := r.Context().Value(c.BodyCtxKey).([]byte) bodyBytes, _ := r.Context().Value(c.BodyCtxKey).([]byte)
if validationSchema != "" { if validationSchema != "" {
@ -176,10 +176,10 @@ func fillObjectFromBody(w http.ResponseWriter, r *http.Request, validationSchema
return true return true
} }
func configureCertificate(c certificate.Model) { func configureCertificate(cert certificate.Model) {
err := jobqueue.AddJob(jobqueue.Job{ err := jobqueue.AddJob(jobqueue.Job{
Name: "RequestCertificate", Name: "RequestCertificate",
Action: c.Request, Action: cert.Request,
}) })
if err != nil { if err != nil {
logger.Error("ConfigureCertificateError", err) logger.Error("ConfigureCertificateError", err)

View File

@ -2,6 +2,7 @@ package handler
import ( import (
"net/http" "net/http"
h "npm/internal/api/http" h "npm/internal/api/http"
"npm/internal/config" "npm/internal/config"
) )

View File

@ -2,6 +2,7 @@ package handler
import ( import (
"net/http" "net/http"
"npm/internal/acme" "npm/internal/acme"
h "npm/internal/api/http" h "npm/internal/api/http"
"npm/internal/config" "npm/internal/config"

View File

@ -56,7 +56,7 @@ func getQueryVarInt(r *http.Request, varName string, required bool, defaultValue
} }
func getURLParamInt(r *http.Request, varName string) (uint, error) { func getURLParamInt(r *http.Request, varName string) (uint, error) {
var defaultValue uint = 0 var defaultValue uint
required := true required := true
paramStr := chi.URLParam(r, varName) paramStr := chi.URLParam(r, varName)

View File

@ -3,9 +3,10 @@ package handler
import ( import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"npm/internal/model"
"testing" "testing"
"npm/internal/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -192,7 +192,7 @@ func GetHostNginxConfig(format string) func(http.ResponseWriter, *http.Request)
return return
} }
if format == "text" { if format == "text" {
h.ResultResponseText(w, r, http.StatusOK, content) h.ResultResponseText(w, http.StatusOK, content)
return return
} }
h.ResultResponseJSON(w, r, http.StatusOK, content) h.ResultResponseJSON(w, r, http.StatusOK, content)
@ -202,11 +202,11 @@ func GetHostNginxConfig(format string) func(http.ResponseWriter, *http.Request)
} }
} }
func configureHost(h host.Model) { func configureHost(hst host.Model) {
err := jobqueue.AddJob(jobqueue.Job{ err := jobqueue.AddJob(jobqueue.Job{
Name: "NginxConfigureHost", Name: "NginxConfigureHost",
Action: func() error { Action: func() error {
return nginx.ConfigureHost(h) return nginx.ConfigureHost(hst)
}, },
}) })
if err != nil { if err != nil {

View File

@ -12,7 +12,7 @@ import (
"npm/internal/config" "npm/internal/config"
"npm/internal/logger" "npm/internal/logger"
jsref "github.com/jc21/jsref" "github.com/jc21/jsref"
"github.com/jc21/jsref/provider" "github.com/jc21/jsref/provider"
) )
@ -24,7 +24,7 @@ var (
// Schema simply reads the swagger schema from disk and returns is raw // Schema simply reads the swagger schema from disk and returns is raw
// Route: GET /schema // Route: GET /schema
func Schema() func(http.ResponseWriter, *http.Request) { func Schema() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(getSchema())) fmt.Fprint(w, string(getSchema()))
@ -42,8 +42,8 @@ func getSchema() []byte {
swaggerSchema = []byte(strings.ReplaceAll(string(swaggerSchema), "{{VERSION}}", config.Version)) swaggerSchema = []byte(strings.ReplaceAll(string(swaggerSchema), "{{VERSION}}", config.Version))
// Dereference the JSON Schema: // Dereference the JSON Schema:
var schema interface{} var sch any
if err := json.Unmarshal(swaggerSchema, &schema); err != nil { if err := json.Unmarshal(swaggerSchema, &sch); err != nil {
logger.Error("SwaggerUnmarshalError", err) logger.Error("SwaggerUnmarshalError", err)
return nil return nil
} }
@ -55,7 +55,7 @@ func getSchema() []byte {
logger.Error("SchemaProviderError", err) logger.Error("SchemaProviderError", err)
} }
result, err := resolver.Resolve(schema, "", []jsref.Option{jsref.WithRecursiveResolution(true)}...) result, err := resolver.Resolve(sch, "", []jsref.Option{jsref.WithRecursiveResolution(true)}...)
if err != nil { if err != nil {
logger.Error("SwaggerResolveError", err) logger.Error("SwaggerResolveError", err)
} else { } else {

View File

@ -95,7 +95,7 @@ func CreateUpstream() func(http.ResponseWriter, *http.Request) {
} }
} }
// UpdateHost updates a host // UpdateUpstream updates a stream
// Route: PUT /upstreams/{upstreamID} // Route: PUT /upstreams/{upstreamID}
func UpdateUpstream() func(http.ResponseWriter, *http.Request) { func UpdateUpstream() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
@ -167,7 +167,7 @@ func DeleteUpstream() func(http.ResponseWriter, *http.Request) {
} }
} }
// GetHostNginxConfig will return a Host's nginx config from disk // GetUpstreamNginxConfig will return a Host's nginx config from disk
// Route: GET /upstreams/{upstreamID}/nginx-config // Route: GET /upstreams/{upstreamID}/nginx-config
// Route: GET /upstreams/{upstreamID}/nginx-config.txt // Route: GET /upstreams/{upstreamID}/nginx-config.txt
func GetUpstreamNginxConfig(format string) func(http.ResponseWriter, *http.Request) { func GetUpstreamNginxConfig(format string) func(http.ResponseWriter, *http.Request) {
@ -191,7 +191,7 @@ func GetUpstreamNginxConfig(format string) func(http.ResponseWriter, *http.Reque
return return
} }
if format == "text" { if format == "text" {
h.ResultResponseText(w, r, http.StatusOK, content) h.ResultResponseText(w, http.StatusOK, content)
return return
} }
h.ResultResponseJSON(w, r, http.StatusOK, content) h.ResultResponseJSON(w, r, http.StatusOK, content)

View File

@ -21,19 +21,19 @@ var (
// Response interface for standard API results // Response interface for standard API results
type Response struct { type Response struct {
Result interface{} `json:"result"` Result any `json:"result"`
Error interface{} `json:"error,omitempty"` Error any `json:"error,omitempty"`
} }
// ErrorResponse interface for errors returned via the API // ErrorResponse interface for errors returned via the API
type ErrorResponse struct { type ErrorResponse struct {
Code interface{} `json:"code"` Code any `json:"code"`
Message interface{} `json:"message"` Message any `json:"message"`
Invalid interface{} `json:"invalid,omitempty"` Invalid any `json:"invalid,omitempty"`
} }
// ResultResponseJSON will write the result as json to the http output // ResultResponseJSON will write the result as json to the http output
func ResultResponseJSON(w http.ResponseWriter, r *http.Request, status int, result interface{}) { func ResultResponseJSON(w http.ResponseWriter, r *http.Request, status int, result any) {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status) w.WriteHeader(status)
@ -77,7 +77,7 @@ func ResultSchemaErrorJSON(w http.ResponseWriter, r *http.Request, errs []jsonsc
} }
// ResultErrorJSON will format the result as a standard error object and send it for output // ResultErrorJSON will format the result as a standard error object and send it for output
func ResultErrorJSON(w http.ResponseWriter, r *http.Request, status int, message string, extended interface{}) { func ResultErrorJSON(w http.ResponseWriter, r *http.Request, status int, message string, extended any) {
errorResponse := ErrorResponse{ errorResponse := ErrorResponse{
Code: status, Code: status,
Message: message, Message: message,
@ -98,7 +98,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) {
} }
// ResultResponseText will write the result as text to the http output // ResultResponseText will write the result as text to the http output
func ResultResponseText(w http.ResponseWriter, r *http.Request, status int, content string) { func ResultResponseText(w http.ResponseWriter, status int, content string) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(status) w.WriteHeader(status)
fmt.Fprint(w, content) fmt.Fprint(w, content)

View File

@ -21,7 +21,7 @@ func TestResultResponseJSON(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
status int status int
given interface{} given any
want string want string
}{ }{
{ {
@ -34,9 +34,9 @@ func TestResultResponseJSON(t *testing.T) {
name: "detailed response", name: "detailed response",
status: http.StatusBadRequest, status: http.StatusBadRequest,
given: user.Model{ given: user.Model{
ModelBase: model.ModelBase{ID: 10}, Base: model.Base{ID: 10},
Email: "me@example.com", Email: "me@example.com",
Name: "John Doe", Name: "John Doe",
}, },
want: "{\"result\":{\"id\":10,\"created_at\":0,\"updated_at\":0,\"name\":\"John Doe\",\"email\":\"me@example.com\",\"is_disabled\":false,\"gravatar_url\":\"\"}}", want: "{\"result\":{\"id\":10,\"created_at\":0,\"updated_at\":0,\"name\":\"John Doe\",\"email\":\"me@example.com\",\"is_disabled\":false,\"gravatar_url\":\"\"}}",
}, },
@ -118,7 +118,7 @@ func TestResultErrorJSON(t *testing.T) {
name string name string
status int status int
message string message string
extended interface{} extended any
want string want string
}{ }{
{ {
@ -180,9 +180,8 @@ func TestResultResponseText(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
t.Run("basic test", func(t *testing.T) { t.Run("basic test", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ResultResponseText(w, r, http.StatusOK, "omg this works") ResultResponseText(w, http.StatusOK, "omg this works")
res := w.Result() res := w.Result()
defer res.Body.Close() defer res.Body.Close()
body, err := io.ReadAll(res.Body) body, err := io.ReadAll(res.Body)

View File

@ -15,7 +15,7 @@ func TestAccessControl(t *testing.T) {
// goleak is used to detect goroutine leaks // goleak is used to detect goroutine leaks
defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
}) })

View File

@ -18,6 +18,6 @@ func AuthCacheInit() {
} }
// AuthCacheSet will store the item in memory for the expiration time // AuthCacheSet will store the item in memory for the expiration time
func AuthCacheSet(k string, x interface{}) { func AuthCacheSet(k string, x any) {
AuthCache.Set(k, x, cache.DefaultExpiration) AuthCache.Set(k, x, cache.DefaultExpiration)
} }

View File

@ -26,7 +26,7 @@ func TestBodyContext(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
// Create a test handler that checks the context for the body data // Create a test handler that checks the context for the body data
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
bodyData := r.Context().Value(c.BodyCtxKey).([]byte) bodyData := r.Context().Value(c.BodyCtxKey).([]byte)
assert.Equal(t, body, bodyData) assert.Equal(t, body, bodyData)
}) })

View File

@ -15,7 +15,7 @@ func TestCors(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Use(middleware.Cors(r)) r.Use(middleware.Cors(r))
r.Get("/test", func(w http.ResponseWriter, r *http.Request) { r.Get("/test", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("test")) w.Write([]byte("test"))
}) })
@ -48,7 +48,7 @@ func TestOptions(t *testing.T) {
r := chi.NewRouter() r := chi.NewRouter()
r.Use(middleware.Options(r)) r.Use(middleware.Options(r))
r.Get("/test", func(w http.ResponseWriter, r *http.Request) { r.Get("/test", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("test")) w.Write([]byte("test"))
}) })

View File

@ -5,11 +5,11 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/assert"
"go.uber.org/goleak"
"npm/internal/api/middleware" "npm/internal/api/middleware"
"npm/internal/config" "npm/internal/config"
"github.com/stretchr/testify/assert"
"go.uber.org/goleak"
) )
func TestEnforceSetup(t *testing.T) { func TestEnforceSetup(t *testing.T) {
@ -37,7 +37,7 @@ func TestEnforceSetup(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
config.IsSetup = tt.isSetup config.IsSetup = tt.isSetup
handler := middleware.EnforceSetup()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := middleware.EnforceSetup()(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
})) }))

View File

@ -23,7 +23,7 @@ func TestExpansion(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
expand := middleware.GetExpandFromContext(r) expand := middleware.GetExpandFromContext(r)
assert.Equal(t, []string{"item1", "item2"}, expand) assert.Equal(t, []string{"item1", "item2"}, expand)
}) })
@ -39,7 +39,7 @@ func TestExpansion(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
expand := middleware.GetExpandFromContext(r) expand := middleware.GetExpandFromContext(r)
assert.Nil(t, expand) assert.Nil(t, expand)
}) })

View File

@ -21,7 +21,7 @@ import (
// and the sort parameter is valid as well. // and the sort parameter is valid as well.
// After we have determined what the Filters are to be, they are saved on the Context // After we have determined what the Filters are to be, they are saved on the Context
// to be used later in other endpoints. // to be used later in other endpoints.
func ListQuery(obj interface{}) func(http.Handler) http.Handler { func ListQuery(obj any) func(http.Handler) http.Handler {
schemaData := tags.GetFilterSchema(obj) schemaData := tags.GetFilterSchema(obj)
filterMap := tags.GetFilterMap(obj, "") filterMap := tags.GetFilterMap(obj, "")
@ -29,13 +29,13 @@ func ListQuery(obj interface{}) func(http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
ctx, statusCode, errMsg, errors := listQueryFilters(r, ctx, schemaData) ctx, statusCode, errMsg, errors := listQueryFilters(ctx, r, schemaData)
if statusCode > 0 { if statusCode > 0 {
h.ResultErrorJSON(w, r, statusCode, errMsg, errors) h.ResultErrorJSON(w, r, statusCode, errMsg, errors)
return return
} }
ctx, statusCode, errMsg = listQuerySort(r, filterMap, ctx) ctx, statusCode, errMsg = listQuerySort(ctx, r, filterMap)
if statusCode > 0 { if statusCode > 0 {
h.ResultErrorJSON(w, r, statusCode, errMsg, nil) h.ResultErrorJSON(w, r, statusCode, errMsg, nil)
return return
@ -47,9 +47,9 @@ func ListQuery(obj interface{}) func(http.Handler) http.Handler {
} }
func listQuerySort( func listQuerySort(
ctx context.Context,
r *http.Request, r *http.Request,
filterMap map[string]model.FilterMapValue, filterMap map[string]model.FilterMapValue,
ctx context.Context,
) (context.Context, int, string) { ) (context.Context, int, string) {
var sortFields []model.Sort var sortFields []model.Sort
@ -99,10 +99,10 @@ func listQuerySort(
} }
func listQueryFilters( func listQueryFilters(
r *http.Request,
ctx context.Context, ctx context.Context,
r *http.Request,
schemaData string, schemaData string,
) (context.Context, int, string, interface{}) { ) (context.Context, int, string, any) {
reservedFilterKeys := []string{ reservedFilterKeys := []string{
"limit", "limit",
"offset", "offset",

View File

@ -53,7 +53,7 @@ func TestListQuery(t *testing.T) {
ctx = context.WithValue(ctx, c.FiltersCtxKey, tags.GetFilterSchema(testObj)) ctx = context.WithValue(ctx, c.FiltersCtxKey, tags.GetFilterSchema(testObj))
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
handler := middleware.ListQuery(testObj)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := middleware.ListQuery(testObj)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
})) }))

View File

@ -33,7 +33,6 @@ func CheckRequestSchema(ctx context.Context, schemaData string, payload []byte)
func EnforceRequestSchema(schemaData string) func(http.Handler) http.Handler { func EnforceRequestSchema(schemaData string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get content from context // Get content from context
bodyBytes, _ := r.Context().Value(c.BodyCtxKey).([]byte) bodyBytes, _ := r.Context().Value(c.BodyCtxKey).([]byte)

View File

@ -29,7 +29,7 @@ import (
// NewRouter returns a new router object // NewRouter returns a new router object
func NewRouter() http.Handler { func NewRouter() http.Handler {
// Cors // Cors
cors := cors.New(cors.Options{ corss := cors.New(cors.Options{
AllowedOrigins: []string{"*"}, AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-Requested-With"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-Requested-With"},
@ -42,7 +42,7 @@ func NewRouter() http.Handler {
middleware.AccessControl, middleware.AccessControl,
middleware.Cors(r), middleware.Cors(r),
middleware.Options(r), middleware.Options(r),
cors.Handler, corss.Handler,
chiMiddleware.RealIP, chiMiddleware.RealIP,
chiMiddleware.Recoverer, chiMiddleware.Recoverer,
chiMiddleware.Throttle(5), chiMiddleware.Throttle(5),

View File

@ -18,7 +18,7 @@ func CreateDNSProvider() string {
allSchemasWrapped := make([]string, 0) allSchemasWrapped := make([]string, 0)
for providerName, provider := range allProviders { for providerName, provider := range allProviders {
schema, err := provider.GetJsonSchema() schema, err := provider.GetJSONSchema()
if err != nil { if err != nil {
logger.Error("ProviderSchemaError", eris.Wrapf(err, "Invalid Provider Schema for %s: %v", provider.Title, err)) logger.Error("ProviderSchemaError", eris.Wrapf(err, "Invalid Provider Schema for %s: %v", provider.Title, err))
} else { } else {

View File

@ -3,9 +3,10 @@ package schema
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"npm/internal/entity/certificate"
"testing" "testing"
"npm/internal/entity/certificate"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -1,6 +1,6 @@
package schema package schema
// UpdateHostTemplate is the schema for incoming data validation // UpdateNginxTemplate is the schema for incoming data validation
func UpdateNginxTemplate() string { func UpdateNginxTemplate() string {
return ` return `
{ {

View File

@ -23,6 +23,7 @@ func InitArgs(version, commit *string) {
if appArguments.Version { if appArguments.Version {
fmt.Printf("v%s (%s)\n", *version, *commit) fmt.Printf("v%s (%s)\n", *version, *commit)
// nolint: revive
os.Exit(0) os.Exit(0)
} }
} }

View File

@ -2,6 +2,7 @@ package config
import ( import (
"fmt" "fmt"
"npm/internal/logger" "npm/internal/logger"
) )

View File

@ -46,8 +46,8 @@ func SetDB(db *gorm.DB) {
func connect() (*gorm.DB, error) { func connect() (*gorm.DB, error) {
var d gorm.Dialector var d gorm.Dialector
dsn := config.Configuration.DB.GetGormConnectURL() dsn := config.Configuration.DB.GetGormConnectURL()
switch strings.ToLower(config.Configuration.DB.Driver) {
switch strings.ToLower(config.Configuration.DB.Driver) {
case config.DatabaseSqlite: case config.DatabaseSqlite:
// autocreate(dsn) // autocreate(dsn)
d = sqlite.Open(dsn) d = sqlite.Open(dsn)

View File

@ -2,8 +2,9 @@ package database
import ( import (
"fmt" "fmt"
"npm/internal/config"
"strings" "strings"
"npm/internal/config"
) )
const ( const (

View File

@ -9,6 +9,8 @@ import (
"npm/internal/logger" "npm/internal/logger"
"github.com/amacneil/dbmate/v2/pkg/dbmate" "github.com/amacneil/dbmate/v2/pkg/dbmate"
// Drivers:
_ "github.com/amacneil/dbmate/v2/pkg/driver/mysql" _ "github.com/amacneil/dbmate/v2/pkg/driver/mysql"
_ "github.com/amacneil/dbmate/v2/pkg/driver/postgres" _ "github.com/amacneil/dbmate/v2/pkg/driver/postgres"
_ "github.com/amacneil/dbmate/v2/pkg/driver/sqlite" _ "github.com/amacneil/dbmate/v2/pkg/driver/sqlite"

View File

@ -2,6 +2,7 @@ package dnsproviders
import ( import (
"encoding/json" "encoding/json"
"npm/internal/errors" "npm/internal/errors"
) )
@ -31,8 +32,8 @@ type Provider struct {
Properties map[string]providerField `json:"properties"` Properties map[string]providerField `json:"properties"`
} }
// GetJsonSchema encodes this object as JSON string // GetJSONSchema encodes this object as JSON string
func (p *Provider) GetJsonSchema() (string, error) { func (p *Provider) GetJSONSchema() (string, error) {
b, err := json.Marshal(p) b, err := json.Marshal(p)
return string(b), err return string(b), err
} }

View File

@ -1,9 +1,10 @@
package dnsproviders package dnsproviders
import ( import (
"npm/internal/util"
"testing" "testing"
"npm/internal/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/goleak" "go.uber.org/goleak"
) )
@ -13,7 +14,7 @@ func TestAcmeDNSProvider(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
provider := getDNSAcmeDNS() provider := getDNSAcmeDNS()
json, err := provider.GetJsonSchema() json, err := provider.GetJSONSchema()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, `{ assert.Equal(t, `{
"title": "dns_acmedns", "title": "dns_acmedns",

View File

@ -1,9 +1,10 @@
package dnsproviders package dnsproviders
import ( import (
"npm/internal/util"
"testing" "testing"
"npm/internal/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/goleak" "go.uber.org/goleak"
) )
@ -14,7 +15,7 @@ func TestAdProvider(t *testing.T) {
provider := getDNSAd() provider := getDNSAd()
provider.ConvertToUpdatable() provider.ConvertToUpdatable()
json, err := provider.GetJsonSchema() json, err := provider.GetJSONSchema()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, `{ assert.Equal(t, `{
"title": "dns_ad", "title": "dns_ad",

View File

@ -1,9 +1,10 @@
package dnsproviders package dnsproviders
import ( import (
"npm/internal/util"
"testing" "testing"
"npm/internal/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/goleak" "go.uber.org/goleak"
) )
@ -13,7 +14,7 @@ func TestAliProvider(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
provider := getDNSAli() provider := getDNSAli()
json, err := provider.GetJsonSchema() json, err := provider.GetJSONSchema()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, `{ assert.Equal(t, `{
"title": "dns_ali", "title": "dns_ali",

View File

@ -11,7 +11,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
Meta types.JSONB `json:"meta" gorm:"column:meta"` Meta types.JSONB `json:"meta" gorm:"column:meta"`

View File

@ -139,13 +139,11 @@ func (s *testsuite) TestSave() {
func (s *testsuite) TestSetPassword() { func (s *testsuite) TestSetPassword() {
// goleak is used to detect goroutine leaks // goleak is used to detect goroutine leaks
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
m := Model{UserID: 100} m := Model{UserID: 100}
err := m.SetPassword("abc123") err := m.SetPassword("abc123")
require.NoError(s.T(), err) require.NoError(s.T(), err)
assert.Equal(s.T(), TypeLocal, m.Type) assert.Equal(s.T(), TypeLocal, m.Type)
assert.Greater(s.T(), len(m.Secret), 15) assert.Greater(s.T(), len(m.Secret), 15)
} }
func (s *testsuite) TestValidateSecret() { func (s *testsuite) TestValidateSecret() {

View File

@ -22,7 +22,7 @@ func GetByUserIDType(userID uint, authType string) (Model, error) {
return auth, result.Error return auth, result.Error
} }
// GetByUserIDType finds a user by id and type // GetByIdenityType finds a user by identity and type
func GetByIdenityType(identity string, authType string) (Model, error) { func GetByIdenityType(identity string, authType string) (Model, error) {
var auth Model var auth Model
db := database.GetDB() db := database.GetDB()

View File

@ -17,7 +17,7 @@ const (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id"` UserID uint `json:"user_id" gorm:"column:user_id"`
Type string `json:"type" gorm:"column:type;default:local"` Type string `json:"type" gorm:"column:type;default:local"`
Identity string `json:"identity,omitempty" gorm:"column:identity"` Identity string `json:"identity,omitempty" gorm:"column:identity"`

View File

@ -32,9 +32,9 @@ func OAuthCacheInit() {
// OAuthUser is the OAuth User // OAuthUser is the OAuth User
type OAuthUser struct { type OAuthUser struct {
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
Token string `json:"token"` Token string `json:"token"`
Resource map[string]interface{} `json:"resource"` Resource map[string]any `json:"resource"`
} }
// GetResourceField will attempt to get a field from the resource // GetResourceField will attempt to get a field from the resource

View File

@ -105,7 +105,7 @@ func TestGetEmail(t *testing.T) {
{ {
name: "Email in resource", name: "Email in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"email": "user@example.com", "email": "user@example.com",
}, },
}, },
@ -128,7 +128,7 @@ func TestGetEmail(t *testing.T) {
{ {
name: "No email or identifier", name: "No email or identifier",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{}, Resource: map[string]any{},
}, },
expected: "", expected: "",
}, },
@ -151,7 +151,7 @@ func TestGetName(t *testing.T) {
{ {
name: "Nickname in resource", name: "Nickname in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"nickname": "user_nick", "nickname": "user_nick",
}, },
}, },
@ -160,7 +160,7 @@ func TestGetName(t *testing.T) {
{ {
name: "Given name in resource", name: "Given name in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"given_name": "User Given", "given_name": "User Given",
}, },
}, },
@ -169,7 +169,7 @@ func TestGetName(t *testing.T) {
{ {
name: "Name in resource", name: "Name in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"name": "User Name", "name": "User Name",
}, },
}, },
@ -178,7 +178,7 @@ func TestGetName(t *testing.T) {
{ {
name: "Preferred username in resource", name: "Preferred username in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"preferred_username": "preferred_user", "preferred_username": "preferred_user",
}, },
}, },
@ -187,7 +187,7 @@ func TestGetName(t *testing.T) {
{ {
name: "Username in resource", name: "Username in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"username": "user123", "username": "user123",
}, },
}, },
@ -197,14 +197,14 @@ func TestGetName(t *testing.T) {
name: "No name fields in resource, fallback to identifier", name: "No name fields in resource, fallback to identifier",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Identifier: "fallback_identifier", Identifier: "fallback_identifier",
Resource: map[string]interface{}{}, Resource: map[string]any{},
}, },
expected: "fallback_identifier", expected: "fallback_identifier",
}, },
{ {
name: "No name fields and no identifier", name: "No name fields and no identifier",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{}, Resource: map[string]any{},
}, },
expected: "", expected: "",
}, },
@ -212,7 +212,7 @@ func TestGetName(t *testing.T) {
name: "All fields", name: "All fields",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Identifier: "fallback_identifier", Identifier: "fallback_identifier",
Resource: map[string]interface{}{ Resource: map[string]any{
"nickname": "user_nick", "nickname": "user_nick",
"given_name": "User Given", "given_name": "User Given",
"name": "User Name", "name": "User Name",
@ -248,7 +248,7 @@ func TestGetID(t *testing.T) {
{ {
name: "UID in resource", name: "UID in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"uid": "uid123", "uid": "uid123",
}, },
}, },
@ -257,7 +257,7 @@ func TestGetID(t *testing.T) {
{ {
name: "User ID in resource", name: "User ID in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"user_id": "user_id123", "user_id": "user_id123",
}, },
}, },
@ -266,7 +266,7 @@ func TestGetID(t *testing.T) {
{ {
name: "Username in resource", name: "Username in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"username": "username123", "username": "username123",
}, },
}, },
@ -275,7 +275,7 @@ func TestGetID(t *testing.T) {
{ {
name: "Preferred username in resource", name: "Preferred username in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"preferred_username": "preferred_user", "preferred_username": "preferred_user",
}, },
}, },
@ -284,7 +284,7 @@ func TestGetID(t *testing.T) {
{ {
name: "Email in resource", name: "Email in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"email": "user@example.com", "email": "user@example.com",
}, },
}, },
@ -293,7 +293,7 @@ func TestGetID(t *testing.T) {
{ {
name: "Mail in resource", name: "Mail in resource",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{ Resource: map[string]any{
"mail": "mail@example.com", "mail": "mail@example.com",
}, },
}, },
@ -302,7 +302,7 @@ func TestGetID(t *testing.T) {
{ {
name: "No identifier or resource fields", name: "No identifier or resource fields",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Resource: map[string]interface{}{}, Resource: map[string]any{},
}, },
expected: "", expected: "",
}, },
@ -310,7 +310,7 @@ func TestGetID(t *testing.T) {
name: "All fields", name: "All fields",
oauthUser: OAuthUser{ oauthUser: OAuthUser{
Identifier: "user123", Identifier: "user123",
Resource: map[string]interface{}{ Resource: map[string]any{
"uid": "uid123", "uid": "uid123",
"user_id": "user_id123", "user_id": "user_id123",
"username": "username123", "username": "username123",

View File

@ -44,7 +44,7 @@ const (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Type string `json:"type" gorm:"column:type" filter:"type,string"` Type string `json:"type" gorm:"column:type" filter:"type,string"`
CertificateAuthorityID types.NullableDBUint `json:"certificate_authority_id" gorm:"column:certificate_authority_id" filter:"certificate_authority_id,integer"` CertificateAuthorityID types.NullableDBUint `json:"certificate_authority_id" gorm:"column:certificate_authority_id" filter:"certificate_authority_id,integer"`

View File

@ -210,7 +210,7 @@ func (s *testsuite) TestDelete() {
assert.Equal(s.T(), "Unable to delete a new object", err.Error()) assert.Equal(s.T(), "Unable to delete a new object", err.Error())
m2 := Model{ m2 := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
} }

View File

@ -13,7 +13,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
AcmeshServer string `json:"acmesh_server" gorm:"column:acmesh_server" filter:"acmesh_server,string"` AcmeshServer string `json:"acmesh_server" gorm:"column:acmesh_server" filter:"acmesh_server,string"`
CABundle string `json:"ca_bundle" gorm:"column:ca_bundle" filter:"ca_bundle,string"` CABundle string `json:"ca_bundle" gorm:"column:ca_bundle" filter:"ca_bundle,string"`

View File

@ -296,7 +296,7 @@ func (s *testsuite) TestDelete() {
assert.Equal(s.T(), "Unable to delete a new object", err.Error()) assert.Equal(s.T(), "Unable to delete a new object", err.Error())
m2 := Model{ m2 := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
} }

View File

@ -14,7 +14,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
AcmeshName string `json:"acmesh_name" gorm:"column:acmesh_name" filter:"acmesh_name,string"` AcmeshName string `json:"acmesh_name" gorm:"column:acmesh_name" filter:"acmesh_name,string"`
@ -70,8 +70,8 @@ func (m *Model) GetAcmeShEnvVars() ([]string, error) {
return envs, nil return envs, nil
} }
func getEnvsFromMeta(meta interface{}) []string { func getEnvsFromMeta(meta any) []string {
if rec, ok := meta.(map[string]interface{}); ok { if rec, ok := meta.(map[string]any); ok {
envs := make([]string, 0) envs := make([]string, 0)
for key, val := range rec { for key, val := range rec {
if f, ok := val.(string); ok { if f, ok := val.(string); ok {
@ -81,8 +81,8 @@ func getEnvsFromMeta(meta interface{}) []string {
} }
} }
return envs return envs
} else {
logger.Debug("getEnvsFromMeta: meta is not an map of strings")
return nil
} }
logger.Debug("getEnvsFromMeta: meta is not an map of strings")
return nil
} }

View File

@ -6,12 +6,13 @@ import (
) )
// GetFilterMap returns the filter map // GetFilterMap returns the filter map
func GetFilterMap(m interface{}, includeBaseEntity bool) map[string]model.FilterMapValue { // _ was called `includeBaseEntity`
func GetFilterMap(m any, _ bool) map[string]model.FilterMapValue {
filterMap := tags.GetFilterMap(m, "") filterMap := tags.GetFilterMap(m, "")
// TODO: this is done in GetFilterMap isn't it? // TODO: this is done in GetFilterMap isn't it?
// if includeBaseEntity { // if includeBaseEntity {
// return mergeFilterMaps(tags.GetFilterMap(model.ModelBase{}, ""), filterMap) // return mergeFilterMaps(tags.GetFilterMap(model.Base{}, ""), filterMap)
// } // }
return filterMap return filterMap

View File

@ -189,7 +189,7 @@ func (s *testsuite) TestDelete() {
assert.Equal(s.T(), "Unable to delete a new object", err.Error()) assert.Equal(s.T(), "Unable to delete a new object", err.Error())
m2 := Model{ m2 := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
} }
@ -203,7 +203,7 @@ func (s *testsuite) TestGetTemplate() {
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
m := Model{ m := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
CreatedAt: time.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli(), CreatedAt: time.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC).UnixMilli(),
UpdatedAt: time.Date(2018, 8, 12, 7, 30, 24, 16, time.UTC).UnixMilli(), UpdatedAt: time.Date(2018, 8, 12, 7, 30, 24, 16, time.UTC).UnixMilli(),

View File

@ -27,7 +27,7 @@ const (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Type string `json:"type" gorm:"column:type" filter:"type,string"` Type string `json:"type" gorm:"column:type" filter:"type,string"`
NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"` NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"`

View File

@ -14,12 +14,12 @@ type ListResponse struct {
Limit int `json:"limit"` Limit int `json:"limit"`
Sort []model.Sort `json:"sort"` Sort []model.Sort `json:"sort"`
Filter []model.Filter `json:"filter,omitempty"` Filter []model.Filter `json:"filter,omitempty"`
Items interface{} `json:"items,omitempty"` Items any `json:"items,omitempty"`
} }
// ListQueryBuilder is used to setup queries for lists // ListQueryBuilder is used to setup queries for lists
func ListQueryBuilder( func ListQueryBuilder(
pageInfo *model.PageInfo, _ *model.PageInfo,
filters []model.Filter, filters []model.Filter,
filterMap map[string]model.FilterMapValue, filterMap map[string]model.FilterMapValue,
) *gorm.DB { ) *gorm.DB {

View File

@ -9,7 +9,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
Type string `json:"type" gorm:"column:type" filter:"type,string"` Type string `json:"type" gorm:"column:type" filter:"type,string"`

View File

@ -10,6 +10,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// ScopeOffsetLimit ...
func ScopeOffsetLimit(pageInfo *model.PageInfo) func(db *gorm.DB) *gorm.DB { func ScopeOffsetLimit(pageInfo *model.PageInfo) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB { return func(db *gorm.DB) *gorm.DB {
if pageInfo.Offset > 0 || pageInfo.Limit > 0 { if pageInfo.Offset > 0 || pageInfo.Limit > 0 {
@ -19,6 +20,7 @@ func ScopeOffsetLimit(pageInfo *model.PageInfo) func(db *gorm.DB) *gorm.DB {
} }
} }
// ScopeOrderBy ...
func ScopeOrderBy(sort []model.Sort, defaultSort model.Sort) func(db *gorm.DB) *gorm.DB { func ScopeOrderBy(sort []model.Sort, defaultSort model.Sort) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB { return func(db *gorm.DB) *gorm.DB {
if sort != nil { if sort != nil {
@ -36,6 +38,7 @@ func ScopeOrderBy(sort []model.Sort, defaultSort model.Sort) func(db *gorm.DB) *
} }
} }
// ScopeFilters ...
func ScopeFilters(filters []model.Filter, filterMap map[string]model.FilterMapValue) func(db *gorm.DB) *gorm.DB { func ScopeFilters(filters []model.Filter, filterMap map[string]model.FilterMapValue) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB { return func(db *gorm.DB) *gorm.DB {
like := database.GetCaseInsensitiveLike() like := database.GetCaseInsensitiveLike()

View File

@ -11,7 +11,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
Description string `json:"description" gorm:"column:description" filter:"description,string"` Description string `json:"description" gorm:"column:description" filter:"description,string"`
Value datatypes.JSON `json:"value" gorm:"column:value"` Value datatypes.JSON `json:"value" gorm:"column:value"`

View File

@ -10,7 +10,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
ExpiresOn types.DBDate `json:"expires_on" gorm:"column:expires_on" filter:"expires_on,integer"` ExpiresOn types.DBDate `json:"expires_on" gorm:"column:expires_on" filter:"expires_on,integer"`
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Provider string `json:"provider" gorm:"column:provider" filter:"provider,string"` Provider string `json:"provider" gorm:"column:provider" filter:"provider,string"`

View File

@ -17,7 +17,7 @@ import (
// Model is the model // Model is the model
// See: http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream // See: http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
type Model struct { type Model struct {
model.ModelBase model.Base
UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"` UserID uint `json:"user_id" gorm:"column:user_id" filter:"user_id,integer"`
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"` NginxTemplateID uint `json:"nginx_template_id" gorm:"column:nginx_template_id" filter:"nginx_template_id,integer"`

View File

@ -7,7 +7,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
UpstreamID uint `json:"upstream_id" gorm:"column:upstream_id" filter:"upstream_id,integer"` UpstreamID uint `json:"upstream_id" gorm:"column:upstream_id" filter:"upstream_id,integer"`
Server string `json:"server" gorm:"column:server" filter:"server,string"` Server string `json:"server" gorm:"column:server" filter:"server,string"`
Weight int `json:"weight" gorm:"column:weight" filter:"weight,integer"` Weight int `json:"weight" gorm:"column:weight" filter:"weight,integer"`

View File

@ -226,7 +226,7 @@ func (s *testsuite) TestDelete() {
assert.Equal(s.T(), "Unable to delete a new object", err.Error()) assert.Equal(s.T(), "Unable to delete a new object", err.Error())
m2 := Model{ m2 := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
Name: "John Doe", Name: "John Doe",
@ -442,7 +442,7 @@ func (s *testsuite) TestSaveCapabilitiesInvalid() {
// Empty model returns error // Empty model returns error
m := Model{ m := Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
Capabilities: []string{"doesnotexist", "hosts.manage"}, Capabilities: []string{"doesnotexist", "hosts.manage"},

View File

@ -108,7 +108,7 @@ func DeleteAll() error {
// GetCapabilities gets capabilities for a user // GetCapabilities gets capabilities for a user
func GetCapabilities(userID uint) ([]string, error) { func GetCapabilities(userID uint) ([]string, error) {
capabilities := make([]string, 0) capabilities := make([]string, 0)
var hasCapabilities []UserHasCapabilityModel var hasCapabilities []HasCapabilityModel
db := database.GetDB() db := database.GetDB()
if result := db.Where("user_id = ?", userID).Find(&hasCapabilities); result.Error != nil { if result := db.Where("user_id = ?", userID).Find(&hasCapabilities); result.Error != nil {
return nil, result.Error return nil, result.Error

View File

@ -16,7 +16,7 @@ import (
// Model is the model // Model is the model
type Model struct { type Model struct {
model.ModelBase model.Base
Name string `json:"name" gorm:"column:name" filter:"name,string"` Name string `json:"name" gorm:"column:name" filter:"name,string"`
Email string `json:"email" gorm:"column:email" filter:"email,email"` Email string `json:"email" gorm:"column:email" filter:"email,email"`
IsDisabled bool `json:"is_disabled" gorm:"column:is_disabled" filter:"is_disabled,boolean"` IsDisabled bool `json:"is_disabled" gorm:"column:is_disabled" filter:"is_disabled,boolean"`
@ -33,14 +33,14 @@ func (Model) TableName() string {
return "user" return "user"
} }
// UserHasCapabilityModel is the model // HasCapabilityModel is the model
type UserHasCapabilityModel struct { type HasCapabilityModel struct {
UserID uint `json:"user_id" gorm:"column:user_id"` UserID uint `json:"user_id" gorm:"column:user_id"`
CapabilityName string `json:"name" gorm:"column:capability_name"` CapabilityName string `json:"name" gorm:"column:capability_name"`
} }
// TableName overrides the table name used by gorm // TableName overrides the table name used by gorm
func (UserHasCapabilityModel) TableName() string { func (HasCapabilityModel) TableName() string {
return "user_has_capability" return "user_has_capability"
} }
@ -99,15 +99,15 @@ func (m *Model) SetPermissions(permissions []string) error {
db := database.GetDB() db := database.GetDB()
// Wipe out previous permissions // Wipe out previous permissions
if result := db.Where("user_id = ?", m.ID).Delete(&UserHasCapabilityModel{}); result.Error != nil { if result := db.Where("user_id = ?", m.ID).Delete(&HasCapabilityModel{}); result.Error != nil {
return result.Error return result.Error
} }
if len(permissions) > 0 { if len(permissions) > 0 {
// Add new permissions // Add new permissions
objs := []*UserHasCapabilityModel{} objs := []*HasCapabilityModel{}
for _, permission := range permissions { for _, permission := range permissions {
objs = append(objs, &UserHasCapabilityModel{UserID: m.ID, CapabilityName: permission}) objs = append(objs, &HasCapabilityModel{UserID: m.ID, CapabilityName: permission})
} }
if result := db.Create(objs); result.Error != nil { if result := db.Create(objs); result.Error != nil {
return result.Error return result.Error

View File

@ -2,6 +2,7 @@ package jobqueue
import ( import (
"fmt" "fmt"
"npm/internal/logger" "npm/internal/logger"
) )

View File

@ -9,7 +9,7 @@ var currentKeys KeysModel
// KeysModel is the model // KeysModel is the model
type KeysModel struct { type KeysModel struct {
model.ModelBase model.Base
PublicKey string `gorm:"column:public_key"` PublicKey string `gorm:"column:public_key"`
PrivateKey string `gorm:"column:private_key"` PrivateKey string `gorm:"column:private_key"`
} }
@ -19,7 +19,7 @@ func (KeysModel) TableName() string {
return "jwt_keys" return "jwt_keys"
} }
// LoadByID will load from an ID // LoadLatest will load the latest keys
func (m *KeysModel) LoadLatest() error { func (m *KeysModel) LoadLatest() error {
db := database.GetDB() db := database.GetDB()
result := db.Order("created_at DESC").First(&m) result := db.Order("created_at DESC").First(&m)

View File

@ -183,7 +183,7 @@ func (s *testsuite) TestGetPrivateKey() {
// Set currentKeys and try again // Set currentKeys and try again
currentKeys = KeysModel{ currentKeys = KeysModel{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
PrivateKey: s.privateKeyString, PrivateKey: s.privateKeyString,
@ -210,7 +210,7 @@ func (s *testsuite) TestGetPublicKey() {
// Set currentKeys and try again // Set currentKeys and try again
currentKeys = KeysModel{ currentKeys = KeysModel{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
PrivateKey: s.privateKeyString, PrivateKey: s.privateKeyString,
@ -228,7 +228,7 @@ func (s *testsuite) TestGenerate() {
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
currentKeys = KeysModel{ currentKeys = KeysModel{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
PrivateKey: s.privateKeyString, PrivateKey: s.privateKeyString,
@ -236,7 +236,7 @@ func (s *testsuite) TestGenerate() {
} }
usr := user.Model{ usr := user.Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
} }

View File

@ -24,11 +24,11 @@ type Config struct {
// Interface for a logger // Interface for a logger
type Interface interface { type Interface interface {
GetLogLevel() Level GetLogLevel() Level
Debug(format string, args ...interface{}) Debug(format string, args ...any)
Info(format string, args ...interface{}) Info(format string, args ...any)
Warn(format string, args ...interface{}) Warn(format string, args ...any)
Error(errorClass string, err error, args ...interface{}) Error(errorClass string, err error, args ...any)
Errorf(errorClass, format string, err error, args ...interface{}) Errorf(errorClass, format string, err error, args ...any)
} }
// ConfigurableLogger is an interface for a logger that can be configured // ConfigurableLogger is an interface for a logger that can be configured

View File

@ -71,17 +71,17 @@ func GetLogLevel() Level {
} }
// Debug logs if the log level is set to DebugLevel or below. Arguments are handled in the manner of fmt.Printf. // Debug logs if the log level is set to DebugLevel or below. Arguments are handled in the manner of fmt.Printf.
func Debug(format string, args ...interface{}) { func Debug(format string, args ...any) {
logger.Debug(format, args...) logger.Debug(format, args...)
} }
// Info logs if the log level is set to InfoLevel or below. Arguments are handled in the manner of fmt.Printf. // Info logs if the log level is set to InfoLevel or below. Arguments are handled in the manner of fmt.Printf.
func Info(format string, args ...interface{}) { func Info(format string, args ...any) {
logger.Info(format, args...) logger.Info(format, args...)
} }
// Warn logs if the log level is set to WarnLevel or below. Arguments are handled in the manner of fmt.Printf. // Warn logs if the log level is set to WarnLevel or below. Arguments are handled in the manner of fmt.Printf.
func Warn(format string, args ...interface{}) { func Warn(format string, args ...any) {
logger.Warn(format, args...) logger.Warn(format, args...)
} }
@ -134,7 +134,7 @@ var logLevels = map[Level]string{
ErrorLevel: "ERROR", ErrorLevel: "ERROR",
} }
func (l *Logger) logLevel(logLevel Level, format string, args ...interface{}) { func (l *Logger) logLevel(logLevel Level, format string, args ...any) {
if logLevel < l.LogThreshold { if logLevel < l.LogThreshold {
return return
} }
@ -146,7 +146,7 @@ func (l *Logger) logLevel(logLevel Level, format string, args ...interface{}) {
if len(args) > 1 { if len(args) > 1 {
args = args[1:] args = args[1:]
} else { } else {
args = []interface{}{} args = []any{}
} }
} }
@ -202,17 +202,17 @@ func (l *Logger) GetLogLevel() Level {
} }
// Debug logs if the log level is set to DebugLevel or below. Arguments are handled in the manner of fmt.Printf. // Debug logs if the log level is set to DebugLevel or below. Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Debug(format string, args ...interface{}) { func (l *Logger) Debug(format string, args ...any) {
l.logLevel(DebugLevel, format, args...) l.logLevel(DebugLevel, format, args...)
} }
// Info logs if the log level is set to InfoLevel or below. Arguments are handled in the manner of fmt.Printf. // Info logs if the log level is set to InfoLevel or below. Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Info(format string, args ...interface{}) { func (l *Logger) Info(format string, args ...any) {
l.logLevel(InfoLevel, format, args...) l.logLevel(InfoLevel, format, args...)
} }
// Warn logs if the log level is set to WarnLevel or below. Arguments are handled in the manner of fmt.Printf. // Warn logs if the log level is set to WarnLevel or below. Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Warn(format string, args ...interface{}) { func (l *Logger) Warn(format string, args ...any) {
l.logLevel(WarnLevel, format, args...) l.logLevel(WarnLevel, format, args...)
} }

View File

@ -4,8 +4,8 @@ import (
"gorm.io/plugin/soft_delete" "gorm.io/plugin/soft_delete"
) )
// ModelBase include common fields for db control // Base include common fields for db control
type ModelBase struct { type Base struct {
ID uint `json:"id" gorm:"column:id;primaryKey" filter:"id,integer"` ID uint `json:"id" gorm:"column:id;primaryKey" filter:"id,integer"`
CreatedAt int64 `json:"created_at" gorm:"<-:create;autoCreateTime:milli;column:created_at" filter:"created_at,date"` CreatedAt int64 `json:"created_at" gorm:"<-:create;autoCreateTime:milli;column:created_at" filter:"created_at,date"`
UpdatedAt int64 `json:"updated_at" gorm:"<-;autoUpdateTime:milli;column:updated_at" filter:"updated_at,date"` UpdatedAt int64 `json:"updated_at" gorm:"<-;autoUpdateTime:milli;column:updated_at" filter:"updated_at,date"`

View File

@ -151,14 +151,14 @@ func ConfigureUpstream(u upstream.Model) error {
return u.Save(true) return u.Save(true)
} }
func getHostFilename(h host.Model, append string) string { func getHostFilename(h host.Model, appends string) string {
confDir := fmt.Sprintf("%s/nginx/hosts", config.Configuration.DataFolder) confDir := fmt.Sprintf("%s/nginx/hosts", config.Configuration.DataFolder)
return fmt.Sprintf("%s/host_%d.conf%s", confDir, h.ID, append) return fmt.Sprintf("%s/host_%d.conf%s", confDir, h.ID, appends)
} }
func getUpstreamFilename(u upstream.Model, append string) string { func getUpstreamFilename(u upstream.Model, appends string) string {
confDir := fmt.Sprintf("%s/nginx/upstreams", config.Configuration.DataFolder) confDir := fmt.Sprintf("%s/nginx/upstreams", config.Configuration.DataFolder)
return fmt.Sprintf("%s/upstream_%d.conf%s", confDir, u.ID, append) return fmt.Sprintf("%s/upstream_%d.conf%s", confDir, u.ID, appends)
} }
func removeHostFiles(h host.Model) { func removeHostFiles(h host.Model) {

View File

@ -1,10 +1,11 @@
package nginx package nginx
import ( import (
"testing"
"npm/internal/entity/host" "npm/internal/entity/host"
"npm/internal/model" "npm/internal/model"
"npm/internal/test" "npm/internal/test"
"testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/goleak" "go.uber.org/goleak"
@ -24,7 +25,7 @@ func TestGetHostFilename(t *testing.T) {
{ {
"test1", "test1",
host.Model{ host.Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
}, },
@ -34,7 +35,7 @@ func TestGetHostFilename(t *testing.T) {
{ {
"test2", "test2",
host.Model{ host.Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 10, ID: 10,
}, },
}, },

View File

@ -54,7 +54,7 @@ server {
IsDisabled: false, IsDisabled: false,
}, },
cert: certificate.Model{ cert: certificate.Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 77, ID: 77,
}, },
Status: certificate.StatusProvided, Status: certificate.StatusProvided,
@ -79,7 +79,7 @@ server {
IsDisabled: false, IsDisabled: false,
}, },
cert: certificate.Model{ cert: certificate.Model{
ModelBase: model.ModelBase{ Base: model.Base{
ID: 66, ID: 66,
}, },
Status: certificate.StatusProvided, Status: certificate.StatusProvided,
@ -108,18 +108,18 @@ server {
}, },
} }
for _, test := range tests { for _, tst := range tests {
t.Run(test.name, func(st *testing.T) { t.Run(tst.name, func(st *testing.T) {
templateData := TemplateData{ templateData := TemplateData{
ConfDir: "/etc/nginx/conf.d", ConfDir: "/etc/nginx/conf.d",
DataDir: "/data", DataDir: "/data",
Host: test.host.GetTemplate(), Host: tst.host.GetTemplate(),
Certificate: test.cert.GetTemplate(), Certificate: tst.cert.GetTemplate(),
} }
output, err := renderTemplate(template, templateData) output, err := renderTemplate(template, templateData)
assert.Equal(t, test.want.err, err) assert.Equal(st, tst.want.err, err)
assert.Equal(t, test.want.output, output) assert.Equal(st, tst.want.output, output)
}) })
} }
} }

View File

@ -26,7 +26,7 @@ func Get() *sse.Server {
if instance == nil { if instance == nil {
instance = sse.NewServer(&sse.Options{ instance = sse.NewServer(&sse.Options{
Logger: logger.Get(), Logger: logger.Get(),
ChannelNameFunc: func(request *http.Request) string { ChannelNameFunc: func(_ *http.Request) string {
return defaultChannel // This is the channel for all updates regardless of visibility return defaultChannel // This is the channel for all updates regardless of visibility
}, },
}) })

View File

@ -14,7 +14,8 @@ import (
"github.com/rotisserie/eris" "github.com/rotisserie/eris"
) )
func GetFilterMap(m interface{}, globalTablePrefix string) map[string]model.FilterMapValue { // GetFilterMap ...
func GetFilterMap(m any, globalTablePrefix string) map[string]model.FilterMapValue {
name := getName(m) name := getName(m)
filterMap := make(map[string]model.FilterMapValue) filterMap := make(map[string]model.FilterMapValue)
@ -39,8 +40,8 @@ func GetFilterMap(m interface{}, globalTablePrefix string) map[string]model.Filt
// If this is an entity model (and it probably is) // If this is an entity model (and it probably is)
// then include the base model as well // then include the base model as well
if strings.Contains(name, ".Model") && !strings.Contains(name, "ModelBase") { if strings.Contains(name, ".Model") && !strings.Contains(name, "Base") {
filterMap = GetFilterMap(model.ModelBase{}, globalTablePrefix) filterMap = GetFilterMap(model.Base{}, globalTablePrefix)
} }
if t.Kind() != reflect.Struct { if t.Kind() != reflect.Struct {
@ -128,7 +129,7 @@ func getFilterTagSchema(filterTag string) string {
// GetFilterSchema creates a jsonschema for validating filters, based on the model // GetFilterSchema creates a jsonschema for validating filters, based on the model
// object given and by reading the struct "filter" tags. // object given and by reading the struct "filter" tags.
func GetFilterSchema(m interface{}) string { func GetFilterSchema(m any) string {
filterMap := GetFilterMap(m, "") filterMap := GetFilterMap(m, "")
schemas := make([]string, 0) schemas := make([]string, 0)

View File

@ -10,7 +10,7 @@ import (
var tagCache map[string]map[string]model.FilterMapValue var tagCache map[string]map[string]model.FilterMapValue
// getName returns the name of the type given // getName returns the name of the type given
func getName(m interface{}) string { func getName(m any) string {
fc := reflect.TypeOf(m) fc := reflect.TypeOf(m)
return fmt.Sprint(fc) return fmt.Sprint(fc)
} }

View File

@ -12,6 +12,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// Setup ...
func Setup() (sqlmock.Sqlmock, error) { func Setup() (sqlmock.Sqlmock, error) {
db, mock, err := sqlmock.New() db, mock, err := sqlmock.New()
if err != nil { if err != nil {
@ -26,6 +27,7 @@ func Setup() (sqlmock.Sqlmock, error) {
return mock, err return mock, err
} }
// InitConfig ...
func InitConfig(t *testing.T, envs ...string) { func InitConfig(t *testing.T, envs ...string) {
if len(envs) > 0 { if len(envs) > 0 {
for _, env := range envs { for _, env := range envs {

View File

@ -18,7 +18,7 @@ func (d DBDate) Value() (driver.Value, error) {
} }
// Scan takes data from the database and modifies it for Go Types // Scan takes data from the database and modifies it for Go Types
func (d *DBDate) Scan(src interface{}) error { func (d *DBDate) Scan(src any) error {
d.Time = time.Unix(src.(int64), 0) d.Time = time.Unix(src.(int64), 0)
return nil return nil
} }

View File

@ -22,7 +22,7 @@ func (d NullableDBInt) Value() (driver.Value, error) {
} }
// Scan takes data from the database and modifies it for Go Types // Scan takes data from the database and modifies it for Go Types
func (d *NullableDBInt) Scan(src interface{}) error { func (d *NullableDBInt) Scan(src any) error {
var i int var i int
switch v := src.(type) { switch v := src.(type) {
case int: case int:

View File

@ -18,16 +18,19 @@ func (d NullableDBUint) Value() (driver.Value, error) {
} }
// According to current database/sql docs, the sql has four builtin functions that // According to current database/sql docs, the sql has four builtin functions that
// returns driver.Value, and the underlying types are `int64`, `float64`, `string` and `bool` // returns driver.Value, and the underlying types are `int64`, `float64`, `string` and `bool`
// nolint: gosec
return driver.Value(int64(d.Uint)), nil return driver.Value(int64(d.Uint)), nil
} }
// Scan takes data from the database and modifies it for Go Types // Scan takes data from the database and modifies it for Go Types
func (d *NullableDBUint) Scan(src interface{}) error { func (d *NullableDBUint) Scan(src any) error {
var i uint var i uint
switch v := src.(type) { switch v := src.(type) {
case int: case int:
// nolint: gosec
i = uint(v) i = uint(v)
case int64: case int64:
// nolint: gosec
i = uint(v) i = uint(v)
case float32: case float32:
i = uint(v) i = uint(v)
@ -35,6 +38,7 @@ func (d *NullableDBUint) Scan(src interface{}) error {
i = uint(v) i = uint(v)
case string: case string:
a, _ := strconv.Atoi(v) a, _ := strconv.Atoi(v)
// nolint: gosec
i = uint(a) i = uint(a)
} }
d.Uint = i d.Uint = i

View File

@ -50,7 +50,7 @@ func TestNullableDBUint_Scan(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input interface{} input any
wantUint uint wantUint uint
wantErr bool wantErr bool
}{ }{

View File

@ -9,18 +9,18 @@ import (
// JSONB can be anything // JSONB can be anything
type JSONB struct { type JSONB struct {
Encoded string `json:"decoded"` Encoded string `json:"decoded"`
Decoded interface{} `json:"encoded"` Decoded any `json:"encoded"`
} }
// Value encodes the type ready for the database // Value encodes the type ready for the database
func (j JSONB) Value() (driver.Value, error) { func (j JSONB) Value() (driver.Value, error) {
json, err := json.Marshal(j.Decoded) jsn, err := json.Marshal(j.Decoded)
return driver.Value(string(json)), err return driver.Value(string(jsn)), err
} }
// Scan takes data from the database and modifies it for Go Types // Scan takes data from the database and modifies it for Go Types
func (j *JSONB) Scan(src interface{}) error { func (j *JSONB) Scan(src any) error {
var jsonb JSONB var jsonb JSONB
var srcString string var srcString string
switch v := src.(type) { switch v := src.(type) {

View File

@ -8,7 +8,7 @@ import (
// TestJSONBValue tests the Value method of the JSONB type // TestJSONBValue tests the Value method of the JSONB type
func TestJSONBValue(t *testing.T) { func TestJSONBValue(t *testing.T) {
j := JSONB{ j := JSONB{
Decoded: map[string]interface{}{ Decoded: map[string]any{
"name": "John", "name": "John",
"age": 30, "age": 30,
}, },
@ -35,7 +35,7 @@ func TestJSONBScan(t *testing.T) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
expectedDecoded := map[string]interface{}{ expectedDecoded := map[string]any{
"name": "John", "name": "John",
"age": 30, "age": 30,
} }
@ -59,7 +59,7 @@ func TestJSONBUnmarshalJSON(t *testing.T) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
expectedDecoded := map[string]interface{}{ expectedDecoded := map[string]any{
"name": "John", "name": "John",
"age": 30, "age": 30,
} }
@ -76,7 +76,7 @@ func TestJSONBUnmarshalJSON(t *testing.T) {
// TestJSONBMarshalJSON tests the MarshalJSON method of the JSONB type // TestJSONBMarshalJSON tests the MarshalJSON method of the JSONB type
func TestJSONBMarshalJSON(t *testing.T) { func TestJSONBMarshalJSON(t *testing.T) {
j := JSONB{ j := JSONB{
Decoded: map[string]interface{}{ Decoded: map[string]any{
"name": "John", "name": "John",
"age": 30, "age": 30,
}, },
@ -113,7 +113,7 @@ func TestJSONBAsStringArray(t *testing.T) {
} }
// Helper function to compare JSON objects // Helper function to compare JSON objects
func jsonEqual(a, b interface{}) bool { func jsonEqual(a, b any) bool {
aJSON, _ := json.Marshal(a) aJSON, _ := json.Marshal(a)
bJSON, _ := json.Marshal(b) bJSON, _ := json.Marshal(b)
return string(aJSON) == string(bJSON) return string(aJSON) == string(bJSON)

View File

@ -23,7 +23,7 @@ func (d NullableDBDate) Value() (driver.Value, error) {
} }
// Scan takes data from the database and modifies it for Go Types // Scan takes data from the database and modifies it for Go Types
func (d *NullableDBDate) Scan(src interface{}) error { func (d *NullableDBDate) Scan(src any) error {
var tme time.Time var tme time.Time
if src != nil { if src != nil {
tme = time.Unix(src.(int64), 0) tme = time.Unix(src.(int64), 0)

View File

@ -1,9 +1,9 @@
package util package util
// FindItemInInterface Find key in interface (recursively) and return value as interface // FindItemInInterface Find key in interface (recursively) and return value as interface
func FindItemInInterface(key string, obj interface{}) (interface{}, bool) { func FindItemInInterface(key string, obj any) (any, bool) {
// if the argument is not a map, ignore it // if the argument is not a map, ignore it
mobj, ok := obj.(map[string]interface{}) mobj, ok := obj.(map[string]any)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -15,14 +15,14 @@ func FindItemInInterface(key string, obj interface{}) (interface{}, bool) {
} }
// if the value is a map, search recursively // if the value is a map, search recursively
if m, ok := v.(map[string]interface{}); ok { if m, ok := v.(map[string]any); ok {
if res, ok := FindItemInInterface(key, m); ok { if res, ok := FindItemInInterface(key, m); ok {
return res, true return res, true
} }
} }
// if the value is an array, search recursively // if the value is an array, search recursively
// from each element // from each element
if va, ok := v.([]interface{}); ok { if va, ok := v.([]any); ok {
for _, a := range va { for _, a := range va {
if res, ok := FindItemInInterface(key, a); ok { if res, ok := FindItemInInterface(key, a); ok {
return res, true return res, true

View File

@ -11,13 +11,13 @@ func TestFindItemInInterface(t *testing.T) {
// goleak is used to detect goroutine leaks // goleak is used to detect goroutine leaks
defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(t, goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
obj := map[string]interface{}{ obj := map[string]any{
"key1": "value1", "key1": "value1",
"key2": 10, "key2": 10,
"key3": map[string]interface{}{ "key3": map[string]any{
"nestedKey": "nestedValue", "nestedKey": "nestedValue",
}, },
"key4": []interface{}{"item1", "item2"}, "key4": []any{"item1", "item2"},
} }
// Test case 1: Key exists at the top level // Test case 1: Key exists at the top level

View File

@ -1,7 +1,7 @@
package util package util
// MapContainsKey is fairly self explanatory // MapContainsKey is fairly self explanatory
func MapContainsKey(dict map[string]interface{}, key string) bool { func MapContainsKey(dict map[string]any, key string) bool {
if _, ok := dict[key]; ok { if _, ok := dict[key]; ok {
return true return true
} }

View File

@ -19,7 +19,7 @@ func TestMapContainsKey(t *testing.T) {
var r rect var r rect
r.width = 5 r.width = 5
r.height = 5 r.height = 5
m := map[string]interface{}{ m := map[string]any{
"rect_width": r.width, "rect_width": r.width,
"rect_height": r.height, "rect_height": r.height,
} }

View File

@ -35,8 +35,8 @@ func ConvertIntSliceToString(slice []int) string {
} }
// ConvertStringSliceToInterface is required in some special cases // ConvertStringSliceToInterface is required in some special cases
func ConvertStringSliceToInterface(slice []string) []interface{} { func ConvertStringSliceToInterface(slice []string) []any {
res := make([]interface{}, len(slice)) res := make([]any, len(slice))
for i := range slice { for i := range slice {
res[i] = slice[i] res[i] = slice[i]
} }

View File

@ -99,11 +99,11 @@ func TestConvertIntSliceToString(t *testing.T) {
func TestConvertStringSliceToInterface(t *testing.T) { func TestConvertStringSliceToInterface(t *testing.T) {
testCases := []struct { testCases := []struct {
input []string input []string
expected []interface{} expected []any
}{ }{
{[]string{"hello", "world"}, []interface{}{"hello", "world"}}, {[]string{"hello", "world"}, []any{"hello", "world"}},
{[]string{"apple", "banana", "cherry"}, []interface{}{"apple", "banana", "cherry"}}, {[]string{"apple", "banana", "cherry"}, []any{"apple", "banana", "cherry"}},
{[]string{}, []interface{}{}}, // Empty slice should return an empty slice {[]string{}, []any{}}, // Empty slice should return an empty slice
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -1,10 +1,11 @@
package validator package validator
import ( import (
"testing"
"npm/internal/entity/nginxtemplate" "npm/internal/entity/nginxtemplate"
"npm/internal/entity/upstream" "npm/internal/entity/upstream"
"npm/internal/entity/upstreamserver" "npm/internal/entity/upstreamserver"
"testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"