func YourchartEnabled(apiKey string) (bool, error) {
	conn, err := api.Conn().SqlConnection()
	if err != nil {
		return false, err
	}

	rows, err := conn.Query(`
		SELECT COUNT(*)
		FROM yourchart_keys
		JOIN api_keys
		ON api_keys.id = yourchart_keys.api_key_id
		WHERE api_keys.key = $1
		`, apiKey)
	if err != nil {
		return false, err
	}
	defer rows.Close()

	var count int
	for rows.Next() {
		if err := rows.Scan(&count); err != nil {
			return false, err
		}
	}

	if err = rows.Err(); err != nil {
		return false, err
	}

	return count > 0, nil
}
func YourchartAuthorized(apiKey string, jobId string) (string, string, error) {
	conn, err := api.Conn().SqlConnection()
	if err != nil {
		return "", "", err
	}

	rows, err := conn.Query(`
		SELECT upstream_job_id, upstream_lab_job_id
		FROM yourchart_job_authorizations
		JOIN api_keys
		ON api_keys.id = yourchart_job_authorizations.api_key_id
		WHERE api_keys.key = $1
		AND job_id = $2
		`, apiKey, jobId)
	if err != nil {
		return "", "", err
	}
	defer rows.Close()

	var upstreamJobId string
	var upstreamLabJobId string
	for rows.Next() {
		if err := rows.Scan(&upstreamJobId, &upstreamLabJobId); err != nil {
			return "", "", err
		}
	}

	if err = rows.Err(); err != nil {
		return "", "", err
	}

	return upstreamJobId, upstreamLabJobId, nil
}
Exemple #3
0
func Search(sourceType string, params *SearchParams, r *http.Request) (map[string]interface{}, error) {
	conn := api.Conn().SearchConnection()

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

	matches := phraseMatches(params.paramSets, r)

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

	result, err := conn.Search("source", sourceType, 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
}
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
}
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 #6
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)
	}
}
Exemple #7
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 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 YourchartAuthorize(apiKey string, jobId string, upstreamJobId string, upstreamLabJobId string) error {
	conn, err := api.Conn().SqlConnection()
	if err != nil {
		return err
	}

	authorizationId := bloomdb.MakeKey(apiKey, jobId)
	createdAt := time.Now().UTC()

	_, err = conn.Exec(`
		INSERT INTO yourchart_job_authorizations (id, api_key_id, job_id, upstream_job_id, upstream_lab_job_id, created_at)
		VALUES ($1, 
			(SELECT id FROM api_keys WHERE key = $2), 
			$3, $4, $5, $6)`, authorizationId, apiKey, jobId, upstreamJobId, upstreamLabJobId, createdAt)
	if err != nil {
		return err
	}

	return nil
}
Exemple #10
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})
}
Exemple #11
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
}
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
}