flamingo.me/flamingo-commerce/v3@v3.11.0/product/interfaces/templatefunctions/findProducts.go (about) 1 package templatefunctions 2 3 import ( 4 "context" 5 "log" 6 "strconv" 7 "strings" 8 9 "flamingo.me/flamingo-commerce/v3/search/utils" 10 11 "flamingo.me/pugtemplate/pugjs" 12 13 "flamingo.me/flamingo/v3/framework/web" 14 15 "flamingo.me/flamingo-commerce/v3/search/domain" 16 17 "flamingo.me/flamingo-commerce/v3/product/application" 18 searchApplication "flamingo.me/flamingo-commerce/v3/search/application" 19 ) 20 21 type ( 22 // FindProducts is exported as a template function 23 FindProducts struct { 24 ProductSearchService *application.ProductSearchService `inject:""` 25 DefaultPaginationConfig *utils.PaginationConfig `inject:""` 26 } 27 28 // filterProcessing to modifiy the searchRequest and the result depending on black-/whitelist 29 filterProcessing struct { 30 buildSearchRequest searchApplication.SearchRequest 31 whiteList []string 32 blackList []string 33 } 34 ) 35 36 // Func defines the find products function 37 func (tf *FindProducts) Func(ctx context.Context) interface{} { 38 39 /* 40 widgetName - used to namespace widget - in case we need pagination 41 config - map with certain keys - used to specify the searchRequest better 42 */ 43 return func(namespace string, configs ...pugjs.Map) *application.SearchResult { 44 searchConfig := make(map[string]string) 45 filterConstrains := make(map[string]string) 46 keyValueFilters := make(map[string][]string) 47 48 for configKey, config := range configs { 49 switch configKey { 50 case 0: 51 searchConfig = config.AsStringMap() 52 case 1: 53 for key, value := range config.AsStringIfaceMap() { 54 switch value := value.(type) { 55 case pugjs.String: 56 keyValueFilters[key] = []string{value.String()} 57 case []string: 58 keyValueFilters[key] = value 59 case []interface{}: 60 var filterValues []string 61 for _, sv := range value { 62 if string, ok := sv.(string); ok { 63 filterValues = append(filterValues, string) 64 } 65 } 66 if len(filterValues) > 0 { 67 keyValueFilters[key] = filterValues 68 } 69 } 70 } 71 72 case 2: 73 filterConstrains = config.AsStringMap() 74 } 75 } 76 77 filterProcessing := newFilterProcessing(web.RequestFromContext(ctx), namespace, searchConfig, keyValueFilters, filterConstrains, tf.DefaultPaginationConfig) 78 79 result, e := tf.ProductSearchService.Find(ctx, &filterProcessing.buildSearchRequest) 80 if e != nil { 81 log.Printf("Error: product.interfaces.templatefunc %v", e) 82 return &application.SearchResult{} 83 } 84 return filterProcessing.modifyResult(result) 85 } 86 } 87 88 func newFilterProcessing(request *web.Request, namespace string, searchConfig map[string]string, keyValueFilters map[string][]string, filterConstrains map[string]string, paginationConfig *utils.PaginationConfig) filterProcessing { 89 var filterProcessing filterProcessing 90 91 // 1- set the originalSearchRequest from given searchConfig and keyValueFilters 92 var searchRequest = searchApplication.SearchRequest{ 93 SortDirection: searchConfig["sortDirection"], 94 SortBy: searchConfig["sortBy"], 95 Query: searchConfig["query"], 96 PaginationConfig: paginationConfig, 97 } 98 99 if searchRequest.PaginationConfig != nil { 100 searchRequest.PaginationConfig.NameSpace = namespace 101 } 102 103 pageSize, err := strconv.Atoi(searchConfig["pageSize"]) 104 if err == nil { 105 searchRequest.PageSize = pageSize 106 } 107 108 searchRequest.AddAdditionalFilters(domain.NewKeyValueFilters(keyValueFilters)...) 109 110 // Set blackList and whiteList, also trim spaces 111 filterProcessing.blackList = strings.Split(filterConstrains["blackList"], ",") 112 for i := range filterProcessing.blackList { 113 filterProcessing.blackList[i] = strings.TrimSpace(filterProcessing.blackList[i]) 114 } 115 if filterProcessing.blackList[0] == "" { 116 filterProcessing.blackList = nil 117 } 118 filterProcessing.whiteList = strings.Split(filterConstrains["whiteList"], ",") 119 for i := range filterProcessing.whiteList { 120 filterProcessing.whiteList[i] = strings.TrimSpace(filterProcessing.whiteList[i]) 121 } 122 if filterProcessing.whiteList[0] == "" { 123 filterProcessing.whiteList = nil 124 } 125 126 // 2 - Use the url parameters to modify the filters: 127 for k, v := range request.QueryAll() { 128 if !strings.HasPrefix(k, namespace) { 129 continue 130 } 131 splitted := strings.SplitN(k, ".", 2) 132 if (namespace != "" && len(splitted) < 2) || (namespace == "" && len(splitted) > 1) { 133 continue 134 } 135 136 var filterKey string 137 if namespace != "" { 138 filterKey = splitted[1] 139 } else { 140 filterKey = splitted[0] 141 } 142 143 if filterKey == "page" && len(v) == 1 { 144 page, _ := strconv.ParseInt(v[0], 10, 64) 145 searchRequest.AddAdditionalFilter(domain.NewPaginationPageFilter(int(page))) 146 continue 147 } 148 149 if filterProcessing.isAllowed(filterKey) { 150 searchRequest.SetAdditionalFilter(domain.NewKeyValueFilter(filterKey, v)) 151 } 152 } 153 filterProcessing.buildSearchRequest = searchRequest 154 return filterProcessing 155 } 156 157 // modifyResult - while check the result against the blacklist/whitelist 158 func (f *filterProcessing) modifyResult(result *application.SearchResult) *application.SearchResult { 159 var newFacetCollection domain.FacetCollection = make(map[string]domain.Facet) 160 for k, facet := range result.Facets { 161 if f.isAllowed(k) { 162 newFacetCollection[k] = facet 163 } 164 } 165 result.Facets = newFacetCollection 166 167 var newSelectedFacets []domain.Facet 168 for _, facet := range result.SearchMeta.SelectedFacets { 169 if f.isAllowed(facet.Name) { 170 newSelectedFacets = append(newSelectedFacets, facet) 171 } 172 } 173 result.SearchMeta.SelectedFacets = newSelectedFacets 174 175 return result 176 } 177 178 // isAllowed - checks the given key against the defined whitelist and blacklist (whitelist preferred) 179 func (f *filterProcessing) isAllowed(key string) bool { 180 if len(f.whiteList) > 0 { 181 for _, wl := range f.whiteList { 182 if wl == key { 183 return true 184 } 185 } 186 return false 187 } else if len(f.blackList) > 0 { 188 for _, wl := range f.blackList { 189 ert := wl == key 190 if ert { 191 return false 192 } 193 } 194 } 195 return true 196 }