func SearchSourceHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	source := strings.ToLower(vars["source"])

	if !validElasticSearchRegexp.MatchString(source) {
		api.Render(w, req, http.StatusOK, map[string]interface{}{
			"meta": map[string]interface{}{
				"rowCount": 0,
			},
			"result": []string{},
		})
		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 {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	api.Render(w, req, http.StatusOK, results)
	return
}
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
}
func SourcesHandler(w http.ResponseWriter, req *http.Request) {

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

	rows, err := conn.Query("SELECT name, last_updated, last_checked FROM search_types")
	if err != nil {
		log.Println(err)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}
	defer rows.Close()

	var (
		source  string
		update  time.Time
		checked time.Time
	)

	var npiUpdated, npiChecked time.Time
	sources := make([]dataSource, 0)
	for rows.Next() {
		err := rows.Scan(&source, &update, &checked)
		if err != nil {
			log.Println(err)
			api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
			return
		}

		// Backcompat Feb 13, 2015
		if source == "usgov.hhs.npi" {
			npiUpdated = update
			npiChecked = checked
		}

		sources = append(sources, dataSource{source, update, checked, "READY"})
	}

	// Backcompat Feb 13, 2015
	sources = append(sources, dataSource{"NPI", npiUpdated, npiChecked, "READY"})

	api.Render(w, req, http.StatusOK, map[string][]dataSource{"result": sources})
}
Exemple #4
0
func (s *Authentication) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	vars := r.URL.Query()
	secret := vars["secret"]

	if len(secret) > 1 {
		api.Render(rw, r, 401, map[string]string{
			"name":    "Unauthorized",
			"message": "Please contact [email protected] if this is in error",
		})
		return
	}

	if len(secret) == 1 {
		conn, err := api.Conn().SqlConnection()
		if err != nil {
			log.Println(err)
			api.Render(rw, r, http.StatusInternalServerError, "Internal Server Error")
			return
		}

		var deactivated bool
		err = conn.QueryRow(`SELECT deactivated FROM api_keys WHERE key = $1`, secret[0]).Scan(&deactivated)
		if err == sql.ErrNoRows {
			api.Render(rw, r, 401, map[string]string{
				"name":    "Unauthorized",
				"message": "Please contact [email protected] if this is in error",
			})
			return
		} else if deactivated {
			api.Render(rw, r, 401, map[string]string{
				"name":    "Deactivated",
				"message": "Your account has been deactivated by BloomAPI admins. Please contact [email protected] for more information",
			})
			return
		} else if err != nil {
			log.Println(err)
			api.Render(rw, r, http.StatusInternalServerError, "Internal Server Error")
			return
		}

		context.Set(r, "api_key", secret[0])
		next(rw, r)
	} else {
		next(rw, r)
	}
}
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
	}
}
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})
}
Exemple #7
0
func (s *Authentication) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	vars := r.URL.Query()
	secret := vars["secret"]

	if len(secret) > 0 && secret[0] != "" {
		api.Render(rw, r, 401, map[string]string{
			"name":    "Unauthorized",
			"message": "Please contact [email protected] if this is in error",
		})
	} else {
		next(rw, r)
	}
}
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
}
Exemple #9
0
func ItemHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	source := strings.ToLower(vars["source"])
	id := vars["id"]

	conn := api.Conn().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
	}

	if source != "usgov.hhs.npi" {
		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 may be rate-limited in the future. For hosted, production access, please email '*****@*****.**' for an API key.")
		api.AddMessage(req, "Warning: This query used the experimental dataset, '"+source+"'. To ensure you're notified in case breaking changes need to be made, email [email protected] and ask for an API key.")
	}

	result, err := conn.Get("source", source, 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.Render(w, req, http.StatusOK, body)
	return
}
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,
	})
}
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)
}
Exemple #12
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
}