Ejemplo n.º 1
0
func NpiSearchHandler(w http.ResponseWriter, req *http.Request) {
	params, err := handler.ParseSearchParams(req.URL.Query())
	if err != nil {
		api.Render(w, req, http.StatusBadRequest, err)
		return
	}

	results, err := handler.Search("usgov.hhs.npi", params, req)
	if err != nil {
		switch err.(type) {
		case api.ParamsError:
			api.Render(w, req, http.StatusBadRequest, err)
			return
		default:
			log.Println(err)
			api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
			return
		}
	}

	valuesToStrings(results)

	api.AddFeature(req, "usgov.hhs.npi")
	api.AddFeature(req, "handler:legacynpi:search")

	api.Render(w, req, http.StatusOK, results)
	return
}
Ejemplo n.º 2
0
func SearchSourceHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	source := strings.ToLower(vars["source"])

	conn := api.Conn()
	apiKey, ok := context.Get(req, "api_key").(string)
	if !ok {
		apiKey = ""
	}

	_, ok, err := conn.SearchTypeWithNameAndKey(source, apiKey)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	params, err := ParseSearchParams(req.URL.Query())
	if err != nil {
		api.Render(w, req, http.StatusBadRequest, err)
		return
	}

	results, err := Search(source, params, req)
	if err != nil {
		if _, ok = err.(api.ParamsError); ok {
			api.Render(w, req, http.StatusBadRequest, err)
		} else {
			log.Println(err)
			api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		}
		return
	}

	api.AddFeature(req, source)
	api.AddFeature(req, "handler:search")

	api.Render(w, req, http.StatusOK, results)
	return
}
Ejemplo n.º 3
0
func (s *RecordFeatures) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	api.AddFeature(r, "query")
	features := api.GetFeatures(r)
	j, _ := json.Marshal(features)
	featureJson := string(j)
	api.StatsLogger().Println(featureJson)
	next(rw, r)
}
Ejemplo n.º 4
0
func NpiItemHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	npi := vars["npi"]

	conn := api.Conn().SearchConnection()

	result, err := conn.Search("usgov.hhs.npi", "main", nil, map[string]interface{}{
		"query": map[string]interface{}{
			"filtered": map[string]interface{}{
				"filter": map[string]interface{}{
					"term": map[string]interface{}{
						"npi": npi,
					},
				},
			},
		},
	})
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	if result.Hits.Total == 0 {
		api.Render(w, req, http.StatusNotFound, "npi not found")
		return
	} else {
		hits := make([]interface{}, len(result.Hits.Hits))
		for i, hit := range result.Hits.Hits {
			var source map[string]interface{}
			json.Unmarshal(*hit.Source, &source)
			hits[i] = source
		}

		body := map[string]interface{}{"result": hits[0]}
		valuesToStrings(body)

		api.AddFeature(req, "usgov.hhs.npi")
		api.AddFeature(req, "handler:legacynpi:item")

		api.Render(w, req, http.StatusOK, body)
		return
	}
}
Ejemplo n.º 5
0
func SourcesHandler(w http.ResponseWriter, req *http.Request) {
	conn := api.Conn()
	apiKey, ok := context.Get(req, "api_key").(string)

	if !ok {
		apiKey = ""
	}

	searchTypes, err := conn.SearchTypesWithKey(apiKey)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	sources := []dataSource{}
	for _, searchType := range searchTypes {
		sources = append(sources, dataSource{
			Source:  searchType.Name,
			Updated: searchType.LastUpdated,
			Checked: searchType.LastChecked,
			Status:  "READY",
		})

		// Backcompat Feb 13, 2015
		if searchType.Name == "usgov.hhs.npi" {
			sources = append(sources, dataSource{
				Source:  "NPI",
				Updated: searchType.LastUpdated,
				Checked: searchType.LastChecked,
				Status:  "READY",
			})
		}
	}

	api.AddFeature(req, "handler:sources")

	api.Render(w, req, http.StatusOK, map[string][]dataSource{"result": sources})
}
Ejemplo n.º 6
0
func YourChartCreateHandler(w http.ResponseWriter, req *http.Request) {
	yourchartUrl := viper.GetString("yourchartUrl")
	//yourchartLabUrl := viper.GetString("yourchartLabUrl")
	username := req.FormValue("username")
	password := req.FormValue("password")
	orgId := req.FormValue("orgId")

	apiKey, ok := context.Get(req, "api_key").(string)

	enabled, err := YourchartEnabled(apiKey)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	if !ok || !enabled {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	jobId := uuid.NewV4().String()

	// Yourchart
	postResp, err := http.PostForm(yourchartUrl, url.Values{
		"username": {username},
		"password": {password},
		"orgId":    {orgId},
	})
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}
	defer postResp.Body.Close()
	body, err := ioutil.ReadAll(postResp.Body)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var decoded map[string]interface{}
	decoder := json.NewDecoder(strings.NewReader(string(body)))
	err = decoder.Decode(&decoded)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var upstreamJobId string
	rawUpstreamJobId, ok := decoded["statusId"]
	if !ok {
		log.Println(errors.New("Unable to get new job's statusId"))
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	// Yourchart Lab!!
	/*postLabResp, err := http.PostForm(yourchartLabUrl, url.Values{
			"username": {username},
			"password": {password},
			"orgId": {orgId},
		})
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}
	defer postLabResp.Body.Close()
	labBody, err := ioutil.ReadAll(postLabResp.Body)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var labDecoded map[string]interface{}
	labDecoder := json.NewDecoder(strings.NewReader(string(labBody)))
	err = labDecoder.Decode(&labDecoded)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var upstreamLabJobId string
	rawUpstreamLabJobId, ok := labDecoded["statusId"]
	if !ok {
		log.Println(errors.New("Unable to get new job's statusId"))
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	switch rawUpstreamLabJobId := rawUpstreamLabJobId.(type) {
	case string:
		upstreamLabJobId = rawUpstreamLabJobId
	case float64:
		upstreamLabJobId = strconv.FormatFloat(rawUpstreamLabJobId, 'f', 0, 64)
	}*/

	switch rawUpstreamJobId := rawUpstreamJobId.(type) {
	case string:
		upstreamJobId = rawUpstreamJobId
	case float64:
		upstreamJobId = strconv.FormatFloat(rawUpstreamJobId, 'f', 0, 64)
	}

	err = YourchartAuthorize(apiKey, jobId, upstreamJobId, "")
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	api.AddFeature(req, "handler:yourchart:create")

	api.Render(w, req, http.StatusOK, map[string]string{
		"statusId": jobId,
	})
}
Ejemplo n.º 7
0
func YourChartFetchHandler(w http.ResponseWriter, req *http.Request) {
	raven.SetHttpContext(raven.NewHttp(req))
	vars := mux.Vars(req)
	yourchartUrl := viper.GetString("yourchartUrl")
	yourchartLabUrl := viper.GetString("yourchartLabUrl")
	id := vars["id"]

	apiKey, ok := context.Get(req, "api_key").(string)

	enabled, err := YourchartEnabled(apiKey)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	upstreamJobId, upstreamLabJobId, err := YourchartAuthorized(apiKey, id)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	if !ok || !enabled || upstreamJobId == "" {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	getResp, err := http.Get(yourchartUrl + "/" + upstreamJobId)
	body, err := ioutil.ReadAll(getResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	var decoded map[string]interface{}
	decoder := json.NewDecoder(strings.NewReader(string(body)))
	err = decoder.Decode(&decoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	api.AddFeature(req, "handler:yourchart:fetch")

	if upstreamLabJobId == "" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	getLabResp, err := http.Get(yourchartLabUrl + "/" + upstreamLabJobId)
	labBody, err := ioutil.ReadAll(getLabResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	var labDecoded map[string]interface{}
	labDecoder := json.NewDecoder(strings.NewReader(string(labBody)))
	err = labDecoder.Decode(&labDecoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	state, ok := decoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	if state != "complete" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	labState, ok := labDecoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	if labState == "pending" {
		api.Render(w, req, http.StatusOK, map[string]string{"state": "authenticated"})
		return
	} else if labState != "complete" {
		raven.CaptureErrorAndWait(errors.New("lab job seems to be in failure state"), nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
		return
	}

	patients := decoded["result"].(map[string]interface{})["patients"].([]interface{})

	for iOne, patient := range patients {
		//name := patient.(map[string]interface{})["name"].(string)
		details := patient.(map[string]interface{})["details"]
		replaced := false

		labPatients := labDecoded["result"].(map[string]interface{})["patients"].([]interface{})
		if len(labPatients) == 0 {
			raven.CaptureErrorAndWait(errors.New("no lab patients returned"), nil)
			api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
			return
		}

		newModel := labPatients[0].(map[string]interface{})["test-results"] != nil

		if newModel && len(patients) != len(labPatients) {
			raven.CaptureErrorAndWait(errors.New("number of patients are different"), nil)
			api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
			return
		}

		if newModel {
			// New version Jan 25, 2016
			for iTwo, labPatient := range labPatients {
				//labName := labPatient.(map[string]interface{})["name"].(string)
				//labDetails := labPatient.(map[string]interface{})["details"]

				if iOne == iTwo {
					if labPatient.(map[string]interface{})["name"] != nil &&
						patient.(map[string]interface{})["name"] != labPatient.(map[string]interface{})["name"] {
						raven.CaptureErrorAndWait(errors.New("multiple patients inproperly matched"), nil)
						api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
						return
					}

					if details != nil {
						details.(map[string]interface{})["test-results"] = labPatient.(map[string]interface{})["test-results"]
					}

					replaced = true
					break
				}
			}
		} else {
			// Previous version
			details.(map[string]interface{})["test-results"] = labDecoded["result"].(map[string]interface{})["patients"]
			replaced = true
		}

		if !replaced {
			log.Println("Failed to match Epic lab service patient to mobile patient")
			raven.CaptureErrorAndWait(errors.New("Failed to match Epic lab service patient to mobile patient"), nil)
			api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"})
			return
		}
	}

	api.Render(w, req, http.StatusOK, decoded)
}
Ejemplo n.º 8
0
func phraseMatches(paramSets []*SearchParamSet, r *http.Request) []interface{} {
	apiKey, ok := context.Get(r, "api_key").(string)
	if !ok {
		apiKey = ""
	}

	elasticPhrases := make([]interface{}, len(paramSets))
	for index, set := range paramSets {
		shouldValues := make([]map[string]interface{}, len(set.Values))
		api.AddFeature(r, "op:"+set.Op)
		for vIndex, value := range set.Values {
			switch set.Op {
			case "eq":
				shouldValues[vIndex] = map[string]interface{}{
					"match_phrase": map[string]interface{}{
						set.Key: value,
					},
				}
			case "fuzzy":
				if apiKey == "" {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessageWithoutKey, "fuzzy"))
				} else {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "fuzzy"))
				}

				shouldValues[vIndex] = map[string]interface{}{
					"fuzzy": map[string]interface{}{
						set.Key: value,
					},
				}
			case "prefix":
				if apiKey == "" {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessageWithoutKey, "prefix"))
				} else {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "prefix"))
				}
				shouldValues[vIndex] = map[string]interface{}{
					"prefix": map[string]interface{}{
						set.Key: strings.ToLower(value),
					},
				}
			case "gte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gte": value,
						},
					},
				}
			case "gt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gt": value,
						},
					},
				}
			case "lte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lte": value,
						},
					},
				}
			case "lt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lt": value,
						},
					},
				}
			}
		}

		elasticPhrases[index] = map[string]interface{}{
			"bool": map[string]interface{}{
				"should": shouldValues,
			},
		}
	}

	return elasticPhrases
}
Ejemplo n.º 9
0
func Search(sourceType string, params *SearchParams, r *http.Request) (map[string]interface{}, error) {
	conn := api.Conn().SearchConnection()

	apiKey, ok := context.Get(r, "api_key").(string)
	if !ok {
		apiKey = ""
	}

	if apiKey == "" {
		api.AddMessage(r, "Warning: Use of the dataset, '"+sourceType+"', without an API key is for development-use only. Use of this API without a key is rate-limited. For hosted, production access, please email '*****@*****.**' for an API key.")
	}

	matches := phraseMatches(params.paramSets, r)

	var order = "asc"
	if params.Order != "" {
		order = params.Order
	}

	query := map[string]interface{}{
		"from": params.Offset,
		"size": params.Limit,
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": matches,
			},
		},
	}

	if params.Sort != "" {
		if _, ok := context.Get(r, "api_key").(string); !ok {
			return nil, api.NewParamsError("'sort' is unsupported without a BloomAPI user account", map[string]string{})
		}

		query["sort"] = map[string]interface{}{
			params.Sort: map[string]interface{}{
				"order": order,
			},
		}

		api.AddFeature(r, "sort")
		api.AddMessage(r, experimentalSort)
	}

	result, err := conn.Search(sourceType, "main", nil, query)
	if err != nil {
		switch terr := err.(type) {
		case elastigo.ESError:
			if esTypeExceptionRegex.MatchString(terr.What) {
				return nil, api.NewParamsError("one or more values were of an unexpected type", map[string]string{})
			} else {
				return nil, err
			}
		default:
			return nil, err
		}
	}

	hits := make([]interface{}, len(result.Hits.Hits))
	for i, hit := range result.Hits.Hits {
		var source map[string]interface{}
		json.Unmarshal(*hit.Source, &source)
		hits[i] = source
	}

	cleanedResult := map[string]interface{}{
		"meta": map[string]interface{}{
			"rowCount": result.Hits.Total,
		},
		"result": hits,
	}

	return cleanedResult, nil
}
Ejemplo n.º 10
0
func ItemHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	source := strings.ToLower(vars["source"])
	id := vars["id"]

	bloomConn := api.Conn()
	searchConn := bloomConn.SearchConnection()

	if !validElasticSearchRegexp.MatchString(source) {
		api.Render(w, req, http.StatusNotFound, "item not found")
		return
	}

	if !validElasticSearchRegexp.MatchString(id) {
		api.Render(w, req, http.StatusNotFound, "item not found")
		return
	}

	apiKey, ok := context.Get(req, "api_key").(string)
	if !ok {
		apiKey = ""
	}
	_, ok, err := bloomConn.SearchTypeWithNameAndKey(source, apiKey)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name":    "Source Not Found",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	if apiKey == "" {
		api.AddMessage(req, "Warning: Use of the dataset, '"+source+"', without an API key is for development-use only. Use of this API without a key without an API key is for development-use only. Use of this API without a key is rate-limited. For hosted, production access, please email '*****@*****.**' for an API key.")
	}

	result, err := searchConn.Get(source, "main", id, nil)
	if err != nil && err.Error() == elastigo.RecordNotFound.Error() {
		api.Render(w, req, http.StatusNotFound, "item not found")
		return
	} else if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var found map[string]interface{}
	err = json.Unmarshal(*result.Source, &found)
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	body := map[string]interface{}{"result": found}

	api.AddFeature(req, "handler:item")
	api.AddFeature(req, source)

	api.Render(w, req, http.StatusOK, body)
	return
}