mirror of
https://github.com/jc21/nginx-proxy-manager.git
synced 2024-08-30 18:22:48 +00:00
Add entity filters back in for api
This commit is contained in:
parent
1ae247b2a6
commit
4b39ef0eba
@ -5,12 +5,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
c "npm/internal/api/context"
|
||||
h "npm/internal/api/http"
|
||||
"npm/internal/entity"
|
||||
"npm/internal/model"
|
||||
"npm/internal/util"
|
||||
"strings"
|
||||
|
||||
"github.com/qri-io/jsonschema"
|
||||
)
|
||||
@ -19,7 +20,9 @@ import (
|
||||
// passed in to this endpoint. This will ensure that the filters are not injecting SQL.
|
||||
// After we have determined what the Filters are to be, they are saved on the Context
|
||||
// to be used later in other endpoints.
|
||||
func Filters(schemaData string) func(http.Handler) http.Handler {
|
||||
func Filters(obj interface{}) func(http.Handler) http.Handler {
|
||||
schemaData := entity.GetFilterSchema(obj, true)
|
||||
|
||||
reservedFilterKeys := []string{
|
||||
"limit",
|
||||
"offset",
|
||||
@ -93,9 +96,10 @@ func Filters(schemaData string) func(http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// todo: populate filters object with the gorm database name
|
||||
|
||||
ctx = context.WithValue(ctx, c.FiltersCtxKey, filters)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
} else {
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
@ -108,8 +112,7 @@ func GetFiltersFromContext(r *http.Request) []model.Filter {
|
||||
filters, ok := r.Context().Value(c.FiltersCtxKey).([]model.Filter)
|
||||
if !ok {
|
||||
// the assertion failed
|
||||
var emptyFilters []model.Filter
|
||||
return emptyFilters
|
||||
return nil
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
@ -8,6 +8,14 @@ import (
|
||||
"npm/internal/api/middleware"
|
||||
"npm/internal/api/schema"
|
||||
"npm/internal/config"
|
||||
"npm/internal/entity/accesslist"
|
||||
"npm/internal/entity/certificate"
|
||||
"npm/internal/entity/certificateauthority"
|
||||
"npm/internal/entity/dnsprovider"
|
||||
"npm/internal/entity/host"
|
||||
"npm/internal/entity/nginxtemplate"
|
||||
"npm/internal/entity/stream"
|
||||
"npm/internal/entity/upstream"
|
||||
"npm/internal/entity/user"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/serverevents"
|
||||
@ -93,9 +101,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
|
||||
r.With(middleware.Enforce(user.CapabilityUsersManage)).Route("/", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityUsersManage), middleware.Filters(user.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityUsersManage)).
|
||||
Get("/", handler.GetUsers())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityUsersManage),
|
||||
middleware.Filters(user.Model{}),
|
||||
).Get("/", handler.GetUsers())
|
||||
|
||||
// Specific Item
|
||||
r.Get("/{userID:[0-9]+}", handler.GetUser())
|
||||
@ -136,9 +145,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Access Lists
|
||||
r.With(middleware.EnforceSetup(true)).Route("/access-lists", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Filters(accesslist.GetFilterSchema()), middleware.Enforce(user.CapabilityAccessListsView)).
|
||||
r.With(middleware.Enforce(user.CapabilityAccessListsView)).
|
||||
Get("/", handler.GetAccessLists())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityAccessListsView),
|
||||
middleware.Filters(accesslist.Model{}),
|
||||
).Get("/", handler.GetAccessLists())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityAccessListsManage), middleware.EnforceRequestSchema(schema.CreateAccessList())).
|
||||
@ -159,9 +169,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// DNS Providers
|
||||
r.With(middleware.EnforceSetup(true)).Route("/dns-providers", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityDNSProvidersView), middleware.Filters(dnsprovider.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityDNSProvidersView)).
|
||||
Get("/", handler.GetDNSProviders())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityDNSProvidersView),
|
||||
middleware.Filters(dnsprovider.Model{}),
|
||||
).Get("/", handler.GetDNSProviders())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityDNSProvidersManage), middleware.EnforceRequestSchema(schema.CreateDNSProvider())).
|
||||
@ -188,9 +199,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Certificate Authorities
|
||||
r.With(middleware.EnforceSetup(true)).Route("/certificate-authorities", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesView), middleware.Filters(certificateauthority.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesView)).
|
||||
Get("/", handler.GetCertificateAuthorities())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityCertificateAuthoritiesView),
|
||||
middleware.Filters(certificateauthority.Model{}),
|
||||
).Get("/", handler.GetCertificateAuthorities())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesManage), middleware.EnforceRequestSchema(schema.CreateCertificateAuthority())).
|
||||
@ -217,9 +229,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Certificates
|
||||
r.With(middleware.EnforceSetup(true)).Route("/certificates", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityCertificatesView), middleware.Filters(certificate.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityCertificatesView)).
|
||||
Get("/", handler.GetCertificates())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityCertificatesView),
|
||||
middleware.Filters(certificate.Model{}),
|
||||
).Get("/", handler.GetCertificates())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityCertificatesManage), middleware.EnforceRequestSchema(schema.CreateCertificate())).
|
||||
@ -243,9 +256,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Hosts
|
||||
r.With(middleware.EnforceSetup(true)).Route("/hosts", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityHostsView), middleware.Filters(host.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityHostsView)).
|
||||
Get("/", handler.GetHosts())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityHostsView),
|
||||
middleware.Filters(host.Model{}),
|
||||
).Get("/", handler.GetHosts())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityHostsManage), middleware.EnforceRequestSchema(schema.CreateHost())).
|
||||
@ -268,9 +282,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Nginx Templates
|
||||
r.With(middleware.EnforceSetup(true)).Route("/nginx-templates", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityNginxTemplatesView), middleware.Filters(nginxtemplate.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityNginxTemplatesView)).
|
||||
Get("/", handler.GetNginxTemplates())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityNginxTemplatesView),
|
||||
middleware.Filters(nginxtemplate.Model{}),
|
||||
).Get("/", handler.GetNginxTemplates())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityNginxTemplatesManage), middleware.EnforceRequestSchema(schema.CreateNginxTemplate())).
|
||||
@ -291,9 +306,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Streams
|
||||
r.With(middleware.EnforceSetup(true)).Route("/streams", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityStreamsView), middleware.Filters(stream.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityStreamsView)).
|
||||
Get("/", handler.GetStreams())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityStreamsView),
|
||||
middleware.Filters(stream.Model{}),
|
||||
).Get("/", handler.GetStreams())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityStreamsManage), middleware.EnforceRequestSchema(schema.CreateStream())).
|
||||
@ -314,9 +330,10 @@ func applyRoutes(r chi.Router) chi.Router {
|
||||
// Upstreams
|
||||
r.With(middleware.EnforceSetup(true)).Route("/upstreams", func(r chi.Router) {
|
||||
// List
|
||||
// r.With(middleware.Enforce(user.CapabilityHostsView), middleware.Filters(upstream.GetFilterSchema())).
|
||||
r.With(middleware.Enforce(user.CapabilityHostsView)).
|
||||
Get("/", handler.GetUpstreams())
|
||||
r.With(
|
||||
middleware.Enforce(user.CapabilityHostsView),
|
||||
middleware.Filters(upstream.Model{}),
|
||||
).Get("/", handler.GetUpstreams())
|
||||
|
||||
// Create
|
||||
r.With(middleware.Enforce(user.CapabilityHostsManage), middleware.EnforceRequestSchema(schema.CreateUpstream())).
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -37,7 +37,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -1,99 +1,28 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"npm/internal/model"
|
||||
)
|
||||
|
||||
// FilterMapFunction is a filter map function
|
||||
type FilterMapFunction func(value []string) []string
|
||||
|
||||
// GenerateSQLFromFilters will return a Query and params for use as WHERE clause in SQL queries
|
||||
// This will use a AND where clause approach.
|
||||
func GenerateSQLFromFilters(filters []model.Filter, fieldMap map[string]string, fieldMapFunctions map[string]FilterMapFunction) (string, []interface{}) {
|
||||
clauses := make([]string, 0)
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
for _, filter := range filters {
|
||||
// Lookup this filter field from the functions map
|
||||
if _, ok := fieldMapFunctions[filter.Field]; ok {
|
||||
filter.Value = fieldMapFunctions[filter.Field](filter.Value)
|
||||
}
|
||||
|
||||
// Lookup this filter field from the name map
|
||||
if _, ok := fieldMap[filter.Field]; ok {
|
||||
filter.Field = fieldMap[filter.Field]
|
||||
}
|
||||
|
||||
// Special case for LIKE queries, the column needs to be uppercase for comparison
|
||||
fieldName := fmt.Sprintf("`%s`", filter.Field)
|
||||
if strings.ToLower(filter.Modifier) == "contains" || strings.ToLower(filter.Modifier) == "starts" || strings.ToLower(filter.Modifier) == "ends" {
|
||||
fieldName = fmt.Sprintf("UPPER(`%s`)", filter.Field)
|
||||
}
|
||||
|
||||
clauses = append(clauses, fmt.Sprintf("%s %s", fieldName, getSQLAssignmentFromModifier(filter, ¶ms)))
|
||||
}
|
||||
|
||||
return strings.Join(clauses, " AND "), params
|
||||
type filterMapValue struct {
|
||||
Type string
|
||||
Field string
|
||||
}
|
||||
|
||||
func getSQLAssignmentFromModifier(filter model.Filter, params *[]interface{}) string {
|
||||
var clause string
|
||||
|
||||
// Quick hacks
|
||||
if filter.Modifier == "in" && len(filter.Value) == 1 {
|
||||
filter.Modifier = "equals"
|
||||
} else if filter.Modifier == "notin" && len(filter.Value) == 1 {
|
||||
filter.Modifier = "not"
|
||||
}
|
||||
|
||||
switch strings.ToLower(filter.Modifier) {
|
||||
default:
|
||||
clause = "= ?"
|
||||
case "not":
|
||||
clause = "!= ?"
|
||||
case "min":
|
||||
clause = ">= ?"
|
||||
case "max":
|
||||
clause = "<= ?"
|
||||
case "greater":
|
||||
clause = "> ?"
|
||||
case "lesser":
|
||||
clause = "< ?"
|
||||
|
||||
// LIKE modifiers:
|
||||
case "contains":
|
||||
*params = append(*params, strings.ToUpper(filter.Value[0]))
|
||||
return "LIKE '%' || ? || '%'"
|
||||
case "starts":
|
||||
*params = append(*params, strings.ToUpper(filter.Value[0]))
|
||||
return "LIKE ? || '%'"
|
||||
case "ends":
|
||||
*params = append(*params, strings.ToUpper(filter.Value[0]))
|
||||
return "LIKE '%' || ?"
|
||||
|
||||
// Array parameter modifiers:
|
||||
case "in":
|
||||
s, p := buildInArray(filter.Value)
|
||||
*params = append(*params, p...)
|
||||
return fmt.Sprintf("IN (%s)", s)
|
||||
case "notin":
|
||||
s, p := buildInArray(filter.Value)
|
||||
*params = append(*params, p...)
|
||||
return fmt.Sprintf("NOT IN (%s)", s)
|
||||
}
|
||||
|
||||
*params = append(*params, filter.Value[0])
|
||||
return clause
|
||||
}
|
||||
|
||||
/*
|
||||
// GetFilterMap returns the filter map
|
||||
func GetFilterMap(m interface{}) map[string]string {
|
||||
var filterMap = make(map[string]string)
|
||||
func GetFilterMap(m interface{}, includeBaseEntity bool) map[string]filterMapValue {
|
||||
filterMap := getFilterMapForInterface(m)
|
||||
if includeBaseEntity {
|
||||
return mergeFilterMaps(getFilterMapForInterface(ModelBase{}), filterMap)
|
||||
}
|
||||
|
||||
return filterMap
|
||||
}
|
||||
|
||||
func getFilterMapForInterface(m interface{}) map[string]filterMapValue {
|
||||
var filterMap = make(map[string]filterMapValue)
|
||||
|
||||
// TypeOf returns the reflection Type that represents the dynamic type of variable.
|
||||
// If variable is a nil interface value, TypeOf returns nil.
|
||||
@ -106,49 +35,37 @@ func GetFilterMap(m interface{}) map[string]string {
|
||||
|
||||
// Get the field tag value
|
||||
filterTag := field.Tag.Get("filter")
|
||||
dbTag := field.Tag.Get("db")
|
||||
dbTag := field.Tag.Get("gorm")
|
||||
if filterTag != "" && dbTag != "" && dbTag != "-" && filterTag != "-" {
|
||||
// db can have many parts, we need to pull out the "column:value" part
|
||||
dbField := field.Name
|
||||
r := regexp.MustCompile(`(?:^|;)column:([^;|$]+)(?:$|;)`)
|
||||
if matches := r.FindStringSubmatch(dbTag); len(matches) > 1 {
|
||||
dbField = matches[1]
|
||||
}
|
||||
// Filter tag can be a 2 part thing: name,type
|
||||
// ie: account_id,integer
|
||||
// So we need to split and use the first part
|
||||
parts := strings.Split(filterTag, ",")
|
||||
filterMap[parts[0]] = dbTag
|
||||
filterMap[filterTag] = dbTag
|
||||
if len(parts) > 1 {
|
||||
filterMap[parts[0]] = filterMapValue{
|
||||
Type: parts[1],
|
||||
Field: dbField,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filterMap
|
||||
}
|
||||
*/
|
||||
|
||||
// GetDBColumns returns the db columns
|
||||
func GetDBColumns(m interface{}) []string {
|
||||
var columns []string
|
||||
t := reflect.TypeOf(m)
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
dbTag := field.Tag.Get("db")
|
||||
if dbTag != "" && dbTag != "-" {
|
||||
columns = append(columns, dbTag)
|
||||
}
|
||||
func mergeFilterMaps(m1 map[string]filterMapValue, m2 map[string]filterMapValue) map[string]filterMapValue {
|
||||
merged := make(map[string]filterMapValue, 0)
|
||||
for k, v := range m1 {
|
||||
merged[k] = v
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
func buildInArray(items []string) (string, []interface{}) {
|
||||
// Query string placeholder
|
||||
strs := make([]string, len(items))
|
||||
for i := 0; i < len(items); i++ {
|
||||
strs[i] = "?"
|
||||
}
|
||||
|
||||
// Params as interface
|
||||
params := make([]interface{}, len(items))
|
||||
for i, v := range items {
|
||||
params[i] = v
|
||||
}
|
||||
|
||||
return strings.Join(strs, ", "), params
|
||||
for key, value := range m2 {
|
||||
merged[key] = value
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
@ -2,52 +2,80 @@ package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"npm/internal/logger"
|
||||
"npm/internal/util"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
// GetFilterSchema creates a jsonschema for validating filters, based on the model
|
||||
// object given and by reading the struct "filter" tags.
|
||||
func GetFilterSchema(m interface{}) string {
|
||||
func GetFilterSchema(m interface{}, includeBaseEntity bool) string {
|
||||
var schemas []string
|
||||
t := reflect.TypeOf(m)
|
||||
|
||||
if t.Kind() != reflect.Struct {
|
||||
logger.Error("GetFilterSchemaError", eris.Errorf("%v type can't have attributes inspected", t.Kind()))
|
||||
return ""
|
||||
}
|
||||
|
||||
// The base entity model
|
||||
if includeBaseEntity {
|
||||
b := reflect.TypeOf(ModelBase{})
|
||||
for i := 0; i < b.NumField(); i++ {
|
||||
bField := b.Field(i)
|
||||
bFilterTag := bField.Tag.Get("filter")
|
||||
if bFilterTag != "" && bFilterTag != "-" {
|
||||
schemas = append(schemas, getFilterTagSchema(bFilterTag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The actual interface
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
filterTag := field.Tag.Get("filter")
|
||||
|
||||
if filterTag != "" && filterTag != "-" {
|
||||
// split out tag value "field,filtreType"
|
||||
// with a default filter type of string
|
||||
items := strings.Split(filterTag, ",")
|
||||
if len(items) == 1 {
|
||||
items = append(items, "string")
|
||||
}
|
||||
|
||||
switch items[1] {
|
||||
case "int":
|
||||
fallthrough
|
||||
case "integer":
|
||||
schemas = append(schemas, intFieldSchema(items[0]))
|
||||
case "bool":
|
||||
fallthrough
|
||||
case "boolean":
|
||||
schemas = append(schemas, boolFieldSchema(items[0]))
|
||||
case "date":
|
||||
schemas = append(schemas, dateFieldSchema(items[0]))
|
||||
case "regex":
|
||||
if len(items) < 3 {
|
||||
items = append(items, ".*")
|
||||
}
|
||||
schemas = append(schemas, regexFieldSchema(items[0], items[2]))
|
||||
|
||||
default:
|
||||
schemas = append(schemas, stringFieldSchema(items[0]))
|
||||
}
|
||||
schemas = append(schemas, getFilterTagSchema(filterTag))
|
||||
}
|
||||
}
|
||||
|
||||
return newFilterSchema(schemas)
|
||||
return util.PrettyPrintJSON(newFilterSchema(schemas))
|
||||
}
|
||||
|
||||
func getFilterTagSchema(filterTag string) string {
|
||||
// split out tag value "field,filtreType"
|
||||
// with a default filter type of string
|
||||
items := strings.Split(filterTag, ",")
|
||||
if len(items) == 1 {
|
||||
items = append(items, "string")
|
||||
}
|
||||
|
||||
switch items[1] {
|
||||
case "number":
|
||||
fallthrough
|
||||
case "int":
|
||||
fallthrough
|
||||
case "integer":
|
||||
return intFieldSchema(items[0])
|
||||
case "bool":
|
||||
fallthrough
|
||||
case "boolean":
|
||||
return boolFieldSchema(items[0])
|
||||
case "date":
|
||||
return dateFieldSchema(items[0])
|
||||
case "regex":
|
||||
if len(items) < 3 {
|
||||
items = append(items, ".*")
|
||||
}
|
||||
return regexFieldSchema(items[0], items[2])
|
||||
|
||||
default:
|
||||
return stringFieldSchema(items[0])
|
||||
}
|
||||
}
|
||||
|
||||
// newFilterSchema is the main method to specify a new Filter Schema for use in Middleware
|
||||
|
@ -23,7 +23,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -27,10 +27,11 @@ func ListQueryBuilder(
|
||||
pageInfo *model.PageInfo,
|
||||
defaultSort model.Sort,
|
||||
filters []model.Filter,
|
||||
filterMap map[string]filterMapValue,
|
||||
) *gorm.DB {
|
||||
scopes := make([]func(*gorm.DB) *gorm.DB, 0)
|
||||
scopes = append(scopes, ScopeOrderBy(pageInfo, defaultSort))
|
||||
scopes = append(scopes, ScopeOffsetLimit(pageInfo))
|
||||
// scopes = append(scopes, ScopeFilters(GetFilterMap(m)))
|
||||
scopes = append(scopes, ScopeFilters(filters, filterMap))
|
||||
return database.GetDB().Scopes(scopes...)
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
|
||||
// ModelBase include common fields for db control
|
||||
type ModelBase struct {
|
||||
ID uint `json:"id" gorm:"column:id;primaryKey"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"<-:create;autoCreateTime:milli;column:created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" gorm:"<-;autoUpdateTime:milli;column:updated_at"`
|
||||
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"`
|
||||
UpdatedAt int64 `json:"updated_at" gorm:"<-;autoUpdateTime:milli;column:updated_at" filter:"updated_at,date"`
|
||||
DeletedAt soft_delete.DeletedAt `json:"-" gorm:"column:is_deleted;softDelete:flag"`
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -1,6 +1,7 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"npm/internal/model"
|
||||
@ -34,17 +35,57 @@ func ScopeOrderBy(pageInfo *model.PageInfo, defaultSort model.Sort) func(db *gor
|
||||
}
|
||||
}
|
||||
|
||||
func ScopeFilters(filters map[string]string) func(db *gorm.DB) *gorm.DB {
|
||||
func ScopeFilters(filters []model.Filter, filterMap map[string]filterMapValue) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
// todo
|
||||
/*
|
||||
if filters != nil {
|
||||
filterMap := GetFilterMap(m)
|
||||
filterQuery, filterParams := GenerateSQLFromFilters(filters, filterMap, filterMapFunctions)
|
||||
whereStrings = []string{filterQuery}
|
||||
params = append(params, filterParams...)
|
||||
for _, f := range filters {
|
||||
// Lookup this filter field from the name map
|
||||
if _, ok := filterMap[f.Field]; ok {
|
||||
f.Field = filterMap[f.Field].Field
|
||||
}
|
||||
*/
|
||||
|
||||
// For boolean fields, the value needs tweaking
|
||||
if filterMap[f.Field].Type == "boolean" {
|
||||
f.Value = parseBoolValue(f.Value[0])
|
||||
}
|
||||
|
||||
// Quick adjustments for commonalities
|
||||
if f.Modifier == "in" && len(f.Value) == 1 {
|
||||
f.Modifier = "equals"
|
||||
} else if f.Modifier == "notin" && len(f.Value) == 1 {
|
||||
f.Modifier = "not"
|
||||
}
|
||||
|
||||
switch strings.ToLower(f.Modifier) {
|
||||
case "not":
|
||||
db.Where(fmt.Sprintf("%s != ?", f.Field), f.Value)
|
||||
case "min":
|
||||
db.Where(fmt.Sprintf("%s >= ?", f.Field), f.Value)
|
||||
case "max":
|
||||
db.Where(fmt.Sprintf("%s <= ?", f.Field), f.Value)
|
||||
case "greater":
|
||||
db.Where(fmt.Sprintf("%s > ?", f.Field), f.Value)
|
||||
case "lesser":
|
||||
db.Where(fmt.Sprintf("%s < ?", f.Field), f.Value)
|
||||
|
||||
// LIKE modifiers:
|
||||
case "contains":
|
||||
db.Where(fmt.Sprintf("%s LIKE ?", f.Field), `%`+f.Value[0]+`%`)
|
||||
case "starts":
|
||||
db.Where(fmt.Sprintf("%s LIKE ?", f.Field), f.Value[0]+`%`)
|
||||
case "ends":
|
||||
db.Where(fmt.Sprintf("%s LIKE ?", f.Field), `%`+f.Value[0])
|
||||
|
||||
// Array parameter modifiers:
|
||||
case "in":
|
||||
db.Where(fmt.Sprintf("%s IN ?", f.Field), f.Value)
|
||||
case "notin":
|
||||
db.Where(fmt.Sprintf("%s NOT IN ?", f.Field), f.Value)
|
||||
|
||||
// Default: equals
|
||||
default:
|
||||
db.Where(fmt.Sprintf("%s = ?", f.Field), f.Value)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
@ -60,3 +101,22 @@ func sortToOrderString(sorts []model.Sort) string {
|
||||
}
|
||||
return strings.Join(strs, ", ")
|
||||
}
|
||||
|
||||
func parseBoolValue(v string) []string {
|
||||
bVal := "0"
|
||||
switch strings.ToLower(v) {
|
||||
case "yes":
|
||||
fallthrough
|
||||
case "true":
|
||||
fallthrough
|
||||
case "on":
|
||||
fallthrough
|
||||
case "t":
|
||||
fallthrough
|
||||
case "1":
|
||||
fallthrough
|
||||
case "y":
|
||||
bVal = "1"
|
||||
}
|
||||
return []string{bVal}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -21,7 +21,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -30,7 +30,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -41,7 +41,7 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
Direction: "ASC",
|
||||
}
|
||||
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters)
|
||||
dbo := entity.ListQueryBuilder(&pageInfo, defaultSort, filters, entity.GetFilterMap(Model{}, true))
|
||||
|
||||
// Get count of items in this search
|
||||
var totalRows int64
|
||||
|
@ -20,7 +20,7 @@ type Model struct {
|
||||
Nickname string `json:"nickname" gorm:"column:nickname" filter:"nickname,string"`
|
||||
Email string `json:"email" gorm:"column:email" filter:"email,email"`
|
||||
IsDisabled bool `json:"is_disabled" gorm:"column:is_disabled" filter:"is_disabled,boolean"`
|
||||
IsSystem bool `json:"is_system,omitempty" gorm:"column:is_system"`
|
||||
IsSystem bool `json:"is_system,omitempty" gorm:"column:is_system" filter:"is_system,boolean"`
|
||||
// Other
|
||||
GravatarURL string `json:"gravatar_url" gorm:"-"`
|
||||
// Expansions
|
||||
|
@ -1,6 +1,9 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"npm/internal/logger"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
@ -22,3 +25,16 @@ func CleanupWhitespace(s string) string {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// PrettyPrintJSON takes a string and as long as it's JSON,
|
||||
// it will return a pretty printed and formatted version
|
||||
func PrettyPrintJSON(s string) string {
|
||||
byt := []byte(s)
|
||||
var prettyJSON bytes.Buffer
|
||||
if err := json.Indent(&prettyJSON, byt, "", " "); err != nil {
|
||||
logger.Debug("Can't pretty print non-json string: %s", s)
|
||||
return s
|
||||
}
|
||||
|
||||
return prettyJSON.String()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user