func searchHandler(w http.ResponseWriter, r *http.Request) { /* ... and we need search to run the environment tests, so here we * go. */ w.Header().Set("Content-Type", "application/json") searchResponse := make(map[string]interface{}) pathArray := splitPath(r.URL.Path) pathArrayLen := len(pathArray) opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID")) if oerr != nil { jsonErrorReport(w, r, oerr.Error(), oerr.Status()) return } /* set up query params for searching */ var ( paramQuery string paramsRows int sortOrder string start int ) r.ParseForm() if q, found := r.Form["q"]; found { if len(q) < 0 { jsonErrorReport(w, r, "No query string specified for search", http.StatusBadRequest) return } paramQuery = q[0] } else if pathArrayLen != 1 { /* default to "*:*" for a search term */ paramQuery = "*:*" } if pr, found := r.Form["rows"]; found { if len(pr) > 0 { paramsRows, _ = strconv.Atoi(pr[0]) } } else { paramsRows = 1000 } // TODO: get a default sort in, once sorting is sorted out. if s, found := r.Form["sort"]; found { if len(s) > 0 { sortOrder = s[0] } else { sortOrder = "id ASC" } } _ = sortOrder if st, found := r.Form["start"]; found { if len(st) > 0 { start, _ = strconv.Atoi(st[0]) } } else { start = 0 } if pathArrayLen == 1 { /* base end points */ switch r.Method { case "GET": if opUser.IsValidator() { jsonErrorReport(w, r, "You are not allowed to perform this action", http.StatusForbidden) return } searchEndpoints := search.GetEndpoints() for _, s := range searchEndpoints { searchResponse[s] = util.CustomURL(fmt.Sprintf("/search/%s", s)) } default: jsonErrorReport(w, r, "Method not allowed", http.StatusMethodNotAllowed) return } } else if pathArrayLen == 2 { switch r.Method { case "GET", "POST": if opUser.IsValidator() { jsonErrorReport(w, r, "You are not allowed to perform this action", http.StatusForbidden) return } /* start figuring out what comes in POSTS now, * so the partial search tests don't complain * anymore. */ var partialData map[string]interface{} if r.Method == "POST" { var perr error partialData, perr = parseObjJSON(r.Body) if perr != nil { jsonErrorReport(w, r, perr.Error(), http.StatusBadRequest) return } } idx := pathArray[1] rObjs, err := search.Search(idx, paramQuery) if err != nil { statusCode := http.StatusBadRequest re := regexp.MustCompile(`^I don't know how to search for .*? data objects.`) if re.MatchString(err.Error()) { statusCode = http.StatusNotFound } jsonErrorReport(w, r, err.Error(), statusCode) return } res := make([]map[string]interface{}, len(rObjs)) for i, r := range rObjs { switch r := r.(type) { case *client.Client: jc := map[string]interface{}{ "name": r.Name, "chef_type": r.ChefType, "json_class": r.JSONClass, "admin": r.Admin, "public_key": r.PublicKey(), "validator": r.Validator, } res[i] = jc default: res[i] = util.MapifyObject(r) } } /* If we're doing partial search, tease out the * fields we want. */ if r.Method == "POST" { res, err = partialSearchFormat(res, partialData) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusBadRequest) return } for x, z := range res { tmpRes := make(map[string]interface{}) switch ro := rObjs[x].(type) { case *databag.DataBagItem: dbiURL := fmt.Sprintf("/data/%s/%s", ro.DataBagName, ro.RawData["id"].(string)) tmpRes["url"] = util.CustomURL(dbiURL) default: tmpRes["url"] = util.ObjURL(rObjs[x].(util.GoiardiObj)) } tmpRes["data"] = z res[x] = tmpRes } } end := start + paramsRows if end > len(res) { end = len(res) } res = res[start:end] searchResponse["total"] = len(res) searchResponse["start"] = start searchResponse["rows"] = res default: jsonErrorReport(w, r, "Method not allowed", http.StatusMethodNotAllowed) return } } else { /* Say what? Bad request. */ jsonErrorReport(w, r, "Bad request", http.StatusBadRequest) return } enc := json.NewEncoder(w) if err := enc.Encode(&searchResponse); err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) } }