コード例 #1
0
ファイル: region.go プロジェクト: nmacnz/geonet-rest
// just quake regions at the moment.
func regions(w http.ResponseWriter, r *http.Request) {
	if err := regionsD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	if r.URL.Query().Get("type") != "quake" {
		web.BadRequest(w, r, "type must be quake.")
		return
	}

	var d string

	err := db.QueryRow(`SELECT row_to_json(fc)
                         FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features
                         FROM (SELECT 'Feature' as type,
                         ST_AsGeoJSON(q.geom)::json as geometry,
                         row_to_json((SELECT l FROM
                         	(
                         		SELECT
                         		regionname as "regionID",
                         		title,
                         		groupname as group
                           ) as l
                         )) as properties FROM qrt.region as q where groupname in ('region', 'north', 'south')) as f ) as fc`).Scan(&d)

	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Surrogate-Control", web.MaxAge86400)
	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #2
0
ファイル: intensity.go プロジェクト: nmacnz/geonet-rest
func intensityMeasuredLatest(w http.ResponseWriter, r *http.Request) {
	if err := intensityMeasuredLatestD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	if r.URL.Query().Get("type") != "measured" {
		web.BadRequest(w, r, "type must be measured.")
		return
	}

	var d string

	err := db.QueryRow(
		`SELECT row_to_json(fc)
				FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features
					FROM (SELECT 'Feature' as type,
						ST_AsGeoJSON(s.location)::json as geometry,
						row_to_json(( select l from 
							( 
								select mmi
								) as l )) 
			as properties from (select location, mmi 
				FROM impact.intensity_measured) as s 
			) As f )  as fc`).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #3
0
ファイル: valid.go プロジェクト: jmptrader/fits
/*
ymin, ymax = 0 - not set
ymin = ymin and != 0 - single range value
ymin != ymax - fixed range
*/
func getYRange(w http.ResponseWriter, r *http.Request) (ymin, ymax float64, ok bool) {
	var err error

	yr := r.URL.Query().Get("yrange")

	switch {
	case yr == "":
		ok = true
	case strings.Contains(yr, `,`):
		y := strings.Split(yr, `,`)
		if len(y) != 2 {
			web.BadRequest(w, r, "invalid yrange query param.")
			return
		}
		ymin, err = strconv.ParseFloat(y[0], 64)
		if err != nil {
			web.BadRequest(w, r, "invalid yrange query param.")
			return
		}
		ymax, err = strconv.ParseFloat(y[1], 64)
		if err != nil {
			web.BadRequest(w, r, "invalid yrange query param.")
			return
		}
	default:
		ymin, err = strconv.ParseFloat(yr, 64)
		if err != nil || ymin <= 0 {
			web.BadRequest(w, r, "invalid yrange query param.")
			return
		}
		ymax = ymin
	}
	ok = true
	return
}
コード例 #4
0
ファイル: quake.go プロジェクト: nmacnz/geonet-rest
func quake(w http.ResponseWriter, r *http.Request) {
	if len(r.URL.Query()) != 0 {
		web.BadRequest(w, r, "incorrect number of query parameters.")
		return
	}

	publicID := r.URL.Path[quakeLen:]

	// TODO bother with this?
	if !publicIDRe.MatchString(publicID) {
		web.BadRequest(w, r, "invalid publicID: "+publicID)
		return
	}

	var d string

	// Check that the publicid exists in the DB.  This is needed as the handle method will return empty
	// JSON for an invalid publicID.
	err := db.QueryRow("select publicid FROM qrt.quake_materialized where publicid = $1", publicID).Scan(&d)
	if err == sql.ErrNoRows {
		web.NotFound(w, r, "invalid publicID: "+publicID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	err = db.QueryRow(
		`SELECT row_to_json(fc)
                         FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features
                         FROM (SELECT 'Feature' as type,
                         ST_AsGeoJSON(q.origin_geom)::json as geometry,
                         row_to_json((SELECT l FROM 
                         	(
                         		SELECT 
                         		publicid AS "publicID",
                                to_char(origintime, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "time",
                                depth, 
                                magnitude, 
                                type, 
                                agency, 
                                locality,
                                qrt.mmi_to_intensity(maxmmi) as intensity,
                                qrt.mmi_to_intensity(mmi_newzealand) as "regionIntensity",
                                qrt.quake_quality(status, usedphasecount, magnitudestationcount) as quality,
                                to_char(updatetime, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "modificationTime"
                           ) as l
                         )) as properties FROM qrt.quake_materialized as q where publicid = $1 ) As f )  as fc`, publicID).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #5
0
ファイル: valid.go プロジェクト: jmptrader/fits
/*
returns a zero length list if no sites are found.
*/
func getSites(w http.ResponseWriter, r *http.Request) ([]siteQ, bool) {
	var sites = make([]siteQ, 0)

	for _, ns := range strings.Split(r.URL.Query().Get("sites"), ",") {
		nss := strings.Split(ns, ".")
		if len(nss) != 2 {
			web.BadRequest(w, r, "invalid sites query.")
			return sites, false
		}
		sites = append(sites, siteQ{networkID: nss[0], siteID: nss[1]})
	}

	for _, s := range sites {
		err := db.QueryRow("select name FROM fits.site join fits.network using (networkpk) where siteid = $2 and networkid = $1", s.networkID, s.siteID).Scan(&s.name)
		if err == sql.ErrNoRows {
			web.NotFound(w, r, "invalid siteID and networkID combination: "+s.siteID+" "+s.networkID)
			return sites, false
		}
		if err != nil {
			web.ServiceUnavailable(w, r, err)
			return sites, false
		}
	}

	return sites, true
}
コード例 #6
0
ファイル: volcano.go プロジェクト: nmacnz/geonet-rest
func alertLevel(w http.ResponseWriter, r *http.Request) {
	if len(r.URL.Query()) != 0 {
		web.BadRequest(w, r, "incorrect number of query parameters.")
		return
	}

	var d string

	err := db.QueryRow(`SELECT row_to_json(fc)
                         FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features
                         FROM (SELECT 'Feature' as type,
                         ST_AsGeoJSON(v.location)::json as geometry,
                         row_to_json((SELECT l FROM 
                         	(
                         		SELECT 
                                id AS "volcanoID",
                                title AS "volcanoTitle",
                                alert_level as "level",
                                activity,
                                hazards 
                           ) as l
                         )) as properties FROM (qrt.volcano JOIN qrt.volcanic_alert_level using (alert_level)) as v ) As f )  as fc`).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #7
0
ファイル: intensity.go プロジェクト: nmacnz/geonet-rest
func intensityReportedLatest(w http.ResponseWriter, r *http.Request) {
	if err := intensityReportedLatestD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	if r.URL.Query().Get("type") != "reported" {
		web.BadRequest(w, r, "type must be reported.")
		return
	}

	zoom := r.URL.Query().Get("zoom")

	if !zoomRe.MatchString(r.URL.Query().Get("zoom")) {
		web.BadRequest(w, r, "Invalid zoom")
		return
	}

	var d string

	err := db.QueryRow(
		`SELECT row_to_json(fc)
						FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features
							FROM (SELECT 'Feature' as type,
								ST_AsGeoJSON(s.location)::json as geometry,
								row_to_json(( select l from 
									( 
										select max_mmi,
										min_mmi,
										count
										) as l )) 
					as properties from (select st_pointfromgeohash(geohash` + zoom + `) as location, 
						min(mmi) as min_mmi, 
						max(mmi) as max_mmi, 
						count(mmi) as count 
						FROM impact.intensity_reported  
						WHERE time >= (now() - interval '60 minutes')
						group by (geohash` + zoom + `)) as s
					) As f )  as fc`).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #8
0
ファイル: site.go プロジェクト: jmptrader/fits
func siteType(w http.ResponseWriter, r *http.Request) {
	if err := siteTypeD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	if v.Get("methodID") != "" && v.Get("typeID") == "" {
		web.BadRequest(w, r, "typeID must be specified when methodID is specified.")
		return
	}

	var typeID, methodID, within string

	if v.Get("typeID") != "" {
		typeID = v.Get("typeID")

		if !validType(w, r, typeID) {
			return
		}

		if v.Get("methodID") != "" {
			methodID = v.Get("methodID")
			if !validTypeMethod(w, r, typeID, methodID) {
				return
			}
		}
	}

	if v.Get("within") != "" {
		within = strings.Replace(v.Get("within"), "+", "", -1)
		if !validPoly(w, r, within) {
			return
		}
	}

	w.Header().Set("Content-Type", web.V1GeoJSON)

	b, err := geoJSONSites(typeID, methodID, within)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}
	web.Ok(w, r, &b)

}
コード例 #9
0
ファイル: valid.go プロジェクト: jmptrader/fits
func getStddev(w http.ResponseWriter, r *http.Request) (string, bool) {
	t := r.URL.Query().Get("stddev")
	switch t {
	case ``, `pop`:
		return t, true
	default:
		web.BadRequest(w, r, "invalid stddev type")
		return ``, false
	}
}
コード例 #10
0
ファイル: valid.go プロジェクト: jmptrader/fits
func getSparkLabel(w http.ResponseWriter, r *http.Request) (string, bool) {
	t := r.URL.Query().Get("label")
	switch t {
	case ``, `all`, `none`, `latest`:
		return t, true
	default:
		web.BadRequest(w, r, "invalid label")
		return ``, false
	}
}
コード例 #11
0
ファイル: valid.go プロジェクト: jmptrader/fits
func getPlotType(w http.ResponseWriter, r *http.Request) (string, bool) {
	t := r.URL.Query().Get("type")
	switch t {
	case ``, `line`, `scatter`:
		return t, true
	default:
		web.BadRequest(w, r, "invalid plot type")
		return ``, false
	}
}
コード例 #12
0
ファイル: region.go プロジェクト: nmacnz/geonet-rest
func region(w http.ResponseWriter, r *http.Request) {
	if len(r.URL.Query()) != 0 {
		web.BadRequest(w, r, "incorrect number of query parameters.")
		return
	}

	regionID := r.URL.Path[regionLen:]

	var d string

	err := db.QueryRow("select regionname FROM qrt.region where regionname = $1", regionID).Scan(&d)
	if err == sql.ErrNoRows {
		web.BadRequest(w, r, "invalid regionID: "+regionID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	err = db.QueryRow(`SELECT row_to_json(fc)
                         FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features
                         FROM (SELECT 'Feature' as type,
                         ST_AsGeoJSON(q.geom)::json as geometry,
                         row_to_json((SELECT l FROM 
                         	(
                         		SELECT 
                         		regionname as "regionID",
                         		title, 
                         		groupname as group
                           ) as l
                         )) as properties FROM qrt.region as q where regionname = $1 ) as f ) as fc`, regionID).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Surrogate-Control", web.MaxAge86400)
	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #13
0
ファイル: valid.go プロジェクト: jmptrader/fits
/*
Returns 0 if days not set
*/
func getDays(w http.ResponseWriter, r *http.Request) (int, bool) {
	var days int
	if r.URL.Query().Get("days") != "" {
		var err error
		days, err = strconv.Atoi(r.URL.Query().Get("days"))
		if err != nil || days > 365000 {
			web.BadRequest(w, r, "Invalid days query param.")
			return 0, false
		}
	}
	return days, true
}
コード例 #14
0
ファイル: routes.go プロジェクト: jmptrader/fits
func router(w http.ResponseWriter, r *http.Request) {

	// requests that don't have a specific version header are routed to the latest version.
	var latest bool
	accept := r.Header.Get("Accept")
	switch accept {
	case web.V1GeoJSON, web.V1JSON, web.V1CSV:
	default:
		latest = true
	}

	switch {
	case r.URL.Path == "/plot":
		if r.URL.Query().Get("siteID") != "" {
			plotSite(w, r)
		} else {
			plotSites(w, r)
		}
	case r.URL.Path == "/spark":
		spark(w, r)
	case r.URL.Path == "/map/site":
		if r.URL.Query().Get("siteID") != "" {
			siteMap(w, r)
		} else if r.URL.Query().Get("sites") != "" {
			siteMap(w, r)
		} else {
			siteTypeMap(w, r)
		}
	case r.URL.Path == "/observation" && (accept == web.V1CSV || latest):
		if r.URL.Query().Get("siteID") != "" {
			observation(w, r)
		} else {
			spatialObs(w, r)
		}
	case r.URL.Path == "/observation/stats" && (accept == web.V1JSON || latest):
		observationStats(w, r)
	case r.URL.Path == "/site" && (accept == web.V1GeoJSON || latest):
		if r.URL.Query().Get("siteID") != "" {
			site(w, r)
		} else {
			siteType(w, r)
		}
	case r.URL.Path == "/type" && (accept == web.V1JSON || latest):
		typeH(w, r)
	case r.URL.Path == "/method" && (accept == web.V1JSON || latest):
		method(w, r)
	case strings.HasPrefix(r.URL.Path, apidoc.Path):
		docs.Serve(w, r)
	default:
		web.BadRequest(w, r, "Can't find a route for this request. Please refer to /api-docs")
	}
}
コード例 #15
0
ファイル: valid.go プロジェクト: jmptrader/fits
/*
Returns zero time if not set.
*/
func getStart(w http.ResponseWriter, r *http.Request) (time.Time, bool) {
	var t time.Time

	if r.URL.Query().Get("start") != "" {
		var err error
		t, err = time.Parse(time.RFC3339, r.URL.Query().Get("start"))
		if err != nil {
			web.BadRequest(w, r, "Invalid start query param.")
			return t, false
		}
	}

	return t, true
}
コード例 #16
0
ファイル: spatialObservations.go プロジェクト: jmptrader/fits
func validPoly(w http.ResponseWriter, r *http.Request, poly string) bool {
	var b bool

	// There is a chance we will return an
	// invalid polygon error for a DB DIal error but in that case something
	// else is about to fail.  Postgis errors are hard to handle via an sql error.
	err := db.QueryRow(`select ST_PolygonFromText($1, 4326) IS NOT NULL AS poly`, poly).Scan(&b)
	if b {
		return true
	}

	web.BadRequest(w, r, "invalid polygon: "+err.Error())
	return false
}
コード例 #17
0
ファイル: felt.go プロジェクト: nmacnz/geonet-rest
func felt(w http.ResponseWriter, r *http.Request) {
	if err := feltD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	publicID := r.URL.Query().Get("publicID")

	var d string

	err := db.QueryRow("select publicid FROM qrt.quake_materialized where publicid = $1", publicID).Scan(&d)
	if err == sql.ErrNoRows {
		web.NotFound(w, r, "invalid publicID: "+publicID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	res, err := client.Get(feltURL + publicID + ".geojson")
	defer res.Body.Close()
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	// Felt returns a 400 when it should probably be a 404.  Tapestry quirk?
	switch {
	case 200 == res.StatusCode:
		web.Ok(w, r, &b)
		return
	case 4 == res.StatusCode/100:
		web.NotFound(w, r, string(b))
		return
	case 5 == res.StatusCode/500:
		web.ServiceUnavailable(w, r, errors.New("error proxying felt resports.  Shrug."))
		return
	}

	web.ServiceUnavailable(w, r, errors.New("unknown response from felt."))
}
コード例 #18
0
ファイル: news.go プロジェクト: nmacnz/geonet-rest
func news(w http.ResponseWriter, r *http.Request) {
	if len(r.URL.Query()) != 0 {
		web.BadRequest(w, r, "incorrect number of query parameters.")
		return
	}

	j, err := fetchRSS(newsURL)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Surrogate-Control", web.MaxAge300)

	web.Ok(w, r, &j)
}
コード例 #19
0
ファイル: spatialObservations.go プロジェクト: jmptrader/fits
// validSrs checks that the srs represented by auth and srid exists in the DB.
func validSrs(w http.ResponseWriter, r *http.Request, auth string, srid int) bool {
	var d string

	err := db.QueryRow(`select auth_name FROM public.spatial_ref_sys where auth_name = $1
		 AND srid = $2`, auth, srid).Scan(&d)
	if err == sql.ErrNoRows {
		web.BadRequest(w, r, "invalid srsName")
		return false
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return false
	}

	return true
}
コード例 #20
0
ファイル: method.go プロジェクト: jmptrader/fits
func method(w http.ResponseWriter, r *http.Request) {
	if err := methodD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	typeID := r.URL.Query().Get("typeID")

	if typeID != "" && !validType(w, r, typeID) {
		return
	}

	var d string
	var err error

	switch typeID {
	case "":
		err = db.QueryRow(
			`select row_to_json(fc) from (select array_to_json(array_agg(m)) as method  
		             from (select methodid as "methodID", method.name, method.description, method.reference 
		             from 
		             fits.type join fits.type_method using (typepk) 
			join fits.method using (methodpk)) as m) as fc`).Scan(&d)
	default:
		err = db.QueryRow(
			`select row_to_json(fc) from (select array_to_json(array_agg(m)) as method  
		             from (select methodid as "methodID", method.name, method.description, method.reference 
		             from 
		             fits.type join fits.type_method using (typepk) 
			join fits.method using (methodpk) 
			where type.typeID = $1) as m) as fc`, typeID).Scan(&d)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return

	}

	w.Header().Set("Content-Type", web.V1JSON)

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #21
0
ファイル: type.go プロジェクト: jmptrader/fits
func typeH(w http.ResponseWriter, r *http.Request) {
	if len(r.URL.Query()) != 0 {
		web.BadRequest(w, r, "incorrect number of query params.")
		return
	}

	w.Header().Set("Content-Type", web.V1JSON)

	var d string

	err := db.QueryRow(
		`select row_to_json(fc) from (select array_to_json(array_agg(t)) as type 
		    from (select typeid as "typeID", type.name, symbol as unit, description 
		    	from fits.type join fits.unit using (unitpk)) as t) as fc`).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #22
0
ファイル: site.go プロジェクト: jmptrader/fits
func site(w http.ResponseWriter, r *http.Request) {
	if err := siteD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	networkID := r.URL.Query().Get("networkID")
	siteID := r.URL.Query().Get("siteID")

	if !validSite(w, r, networkID, siteID) {
		return
	}

	w.Header().Set("Content-Type", web.V1GeoJSON)

	b, err := geoJSONSite(networkID, siteID)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	web.Ok(w, r, &b)
}
コード例 #23
0
ファイル: intensity.go プロジェクト: nmacnz/geonet-rest
func intensityReported(w http.ResponseWriter, r *http.Request) {
	if err := intensityReportedD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	if r.URL.Query().Get("type") != "reported" {
		web.BadRequest(w, r, "type must be reported.")
		return
	}

	zoom := r.URL.Query().Get("zoom")

	if !zoomRe.MatchString(r.URL.Query().Get("zoom")) {
		web.BadRequest(w, r, "Invalid zoom")
		return
	}

	// Check that the publicid exists in the DB.
	// If it does we keep the origintime - we need it later on.
	publicID := r.URL.Query().Get("publicID")

	originTime := time.Time{}

	err := db.QueryRow("select origintime FROM qrt.quake_materialized where publicid = $1", publicID).Scan(&originTime)
	if err == sql.ErrNoRows {
		web.NotFound(w, r, "invalid publicID: "+publicID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	query := `SELECT row_to_json(fc)
				FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features
					FROM (SELECT 'Feature' as type,
						ST_AsGeoJSON(s.location)::json as geometry,
						row_to_json(( select l from 
							( 
							select max_mmi,
							min_mmi,
							count
							) as l )) 
							as properties from (select st_pointfromgeohash(geohash` + zoom + `) as location, 
							min(mmi) as min_mmi, 
							max(mmi) as max_mmi, 
							count(mmi) as count 
							FROM impact.intensity_reported 
							WHERE time >= $1
							AND time <= $2
							group by (geohash` + zoom + `)) as s
			) As f )  as fc`

	var d string

	err = db.QueryRow(query, originTime.Add(time.Duration(-1*time.Minute)), originTime.Add(time.Duration(15*time.Minute))).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := []byte(d)
	web.Ok(w, r, &b)
}
コード例 #24
0
ファイル: routes.go プロジェクト: nmacnz/geonet-rest
func router(w http.ResponseWriter, r *http.Request) {
	// requests that don't have a specific version header are routed to the latest version.
	var latest bool
	accept := r.Header.Get("Accept")
	switch accept {
	case web.V1GeoJSON, web.V1JSON:
	default:
		latest = true
	}

	switch {
	case strings.HasPrefix(r.URL.Path, "/quake") && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		switch {
		case r.URL.Query().Get("intensity") != "":
			quakes(w, r)
		case r.URL.Query().Get("regionIntensity") != "":
			quakesRegion(w, r)
		case strings.HasPrefix(r.URL.Path, "/quake/"):
			quake(w, r)
		default:
			web.BadRequest(w, r, "Can't find a route for this request. Please refer to /api-docs")
		}
	case r.URL.Path == "/intensity" && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		switch {
		case r.URL.Query().Get("type") == "measured":
			intensityMeasuredLatest(w, r)
		// case r.URL.Query().Get("type") == "reported" && r.URL.Query().Get("publicID") == "":
		// 	intensityReportedLatest(w, r)
		// case r.URL.Query().Get("type") == "reported" && r.URL.Query().Get("publicID") != "":
		// 	intensityReported(w, r)
		default:
			web.BadRequest(w, r, "Can't find a route for this request. Please refer to /api-docs")
		}
	case r.URL.Path == "/felt/report" && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		felt(w, r)
	case r.URL.Path == "/volcano/alert/level" && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		alertLevel(w, r)
	case r.URL.Path == "/volcano/alert/bulletin" && (accept == web.V1JSON || latest):
		w.Header().Set("Content-Type", web.V1JSON)
		alertBulletin(w, r)
	case strings.HasPrefix(r.URL.Path, "/region/") && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		region(w, r)
	case r.URL.Path == "/region" && (accept == web.V1GeoJSON || latest):
		w.Header().Set("Content-Type", web.V1GeoJSON)
		regions(w, r)
	case r.URL.Path == "/news/geonet" && (accept == web.V1JSON || latest):
		w.Header().Set("Content-Type", web.V1JSON)
		news(w, r)
	case strings.HasPrefix(r.URL.Path, apidoc.Path):
		docs.Serve(w, r)
	case r.URL.Path == "/soh":
		soh(w, r)
	case r.URL.Path == "/soh/impact":
		impactSOH(w, r)
	default:
		web.BadRequest(w, r, "Can't find a route for this request. Please refer to /api-docs")
	}
}
コード例 #25
0
ファイル: maps.go プロジェクト: jmptrader/fits
func siteMap(w http.ResponseWriter, r *http.Request) {
	if err := siteMapD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	bbox := v.Get("bbox")

	var insetBbox string

	if v.Get("insetBbox") != "" {
		insetBbox = v.Get("insetBbox")

		err := map180.ValidBbox(insetBbox)
		if err != nil {
			web.BadRequest(w, r, err.Error())
			return
		}
	}

	if v.Get("sites") == "" && (v.Get("siteID") == "" && v.Get("networkID") == "") {
		web.BadRequest(w, r, "please specify sites or networkID and siteID")
		return
	}

	if v.Get("sites") != "" && (v.Get("siteID") != "" || v.Get("networkID") != "") {
		web.BadRequest(w, r, "please specify either sites or networkID and siteID")
		return
	}

	if v.Get("sites") == "" && (v.Get("siteID") == "" || v.Get("networkID") == "") {
		web.BadRequest(w, r, "please specify networkID and siteID")
		return
	}

	err := map180.ValidBbox(bbox)
	if err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	width := 130

	if v.Get("width") != "" {
		width, err = strconv.Atoi(v.Get("width"))
		if err != nil {
			web.BadRequest(w, r, "invalid width.")
			return
		}
	}

	var s []st

	if v.Get("sites") != "" {
		for _, ns := range strings.Split(v.Get("sites"), ",") {
			nss := strings.Split(ns, ".")
			if len(nss) != 2 {
				web.BadRequest(w, r, "invalid sites query.")
				return
			}
			s = append(s, st{networkID: nss[0], siteID: nss[1]})
		}
	} else {
		s = append(s, st{networkID: v.Get("networkID"),
			siteID: v.Get("siteID")})
	}

	markers := make([]map180.Marker, 0)

	for _, site := range s {
		if !validSite(w, r, site.networkID, site.siteID) {
			return
		}

		g, err := geoJSONSite(site.networkID, site.siteID)
		if err != nil {
			web.ServiceUnavailable(w, r, err)
			return
		}

		m, err := geoJSONToMarkers(g)
		if err != nil {
			web.ServiceUnavailable(w, r, err)
			return
		}
		markers = append(markers, m...)

	}

	b, err := wm.SVG(bbox, width, markers, insetBbox)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Content-Type", "image/svg+xml")
	web.OkBuf(w, r, &b)
}
コード例 #26
0
ファイル: observation.go プロジェクト: jmptrader/fits
/**
 * query end point for observation statistics including: max, min, mean, std, first and last values
 * http://fits.geonet.org.nz/observation/stats?typeID=e&siteID=HOLD&networkID=CG&days=100
 */
func observationStats(w http.ResponseWriter, r *http.Request) {
	//1. check query parameters
	if err := observationD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	typeID := v.Get("typeID")
	networkID := v.Get("networkID")
	siteID := v.Get("siteID")

	if !validType(w, r, typeID) {
		return
	}

	var days int
	var err error
	var tmin, tmax time.Time

	if v.Get("days") != "" {
		days, err = strconv.Atoi(v.Get("days"))
		if err != nil || days > 365000 {
			web.BadRequest(w, r, "Invalid days query param.")
			return
		}
		tmax = time.Now().UTC()
		tmin = tmax.Add(time.Duration(days*-1) * time.Hour * 24)
	}

	var methodID string

	if v.Get("methodID") != "" {
		methodID = v.Get("methodID")
		if !validTypeMethod(w, r, typeID, methodID) {
			return
		}
	}

	//2. Find the unit
	var unit string
	err = db.QueryRow("select symbol FROM fits.type join fits.unit using (unitPK) where typeID = $1", typeID).Scan(&unit)
	if err == sql.ErrNoRows {
		web.NotFound(w, r, "unit not found for typeID: "+typeID)
		return
	}

	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	// retrieve values using existing functions
	values, err := loadObs(networkID, siteID, typeID, methodID, tmin)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	mean, stdDev, err := stddevPop(networkID, siteID, typeID, methodID, tmin)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}
	stats := obstats{Unit: unit,
		Mean:             mean,
		StddevPopulation: stdDev}

	//4. get maximum, minimum, first, last values
	stats.First = values[0]
	stats.Last = values[len(values)-1]

	iMin, iMax, _ := extremes(values)
	stats.Minimum = values[iMin]
	stats.Maximum = values[iMax]

	//5. send result response
	w.Header().Set("Content-Type", web.V1JSON)
	b, err := json.Marshal(stats)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}
	web.Ok(w, r, &b)
}
コード例 #27
0
ファイル: observation.go プロジェクト: jmptrader/fits
func observation(w http.ResponseWriter, r *http.Request) {
	if err := observationD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	typeID := v.Get("typeID")
	networkID := v.Get("networkID")
	siteID := v.Get("siteID")

	if !validType(w, r, typeID) {
		return
	}

	var days int

	if v.Get("days") != "" {
		var err error
		days, err = strconv.Atoi(v.Get("days"))
		if err != nil || days > 365000 {
			web.BadRequest(w, r, "Invalid days query param.")
			return
		}
	}

	var methodID string

	if v.Get("methodID") != "" {
		methodID = v.Get("methodID")
		if !validTypeMethod(w, r, typeID, methodID) {
			return
		}
	}

	// Find the unit for the CSV header
	var unit string
	err := db.QueryRow("select symbol FROM fits.type join fits.unit using (unitPK) where typeID = $1", typeID).Scan(&unit)
	if err == sql.ErrNoRows {
		web.NotFound(w, r, "unit not found for typeID: "+typeID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	var d string
	var rows *sql.Rows

	switch {
	case days == 0 && methodID == "":
		rows, err = db.Query(
			`SELECT format('%s,%s,%s', to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'), value, error) as csv FROM fits.observation 
                           WHERE 
                               sitepk = (
                                              SELECT DISTINCT ON (sitepk) sitepk from fits.site join fits.network using (networkpk) where siteid = $2 and networkid = $1 
                                            )
                               AND typepk = (
                                                        SELECT typepk FROM fits.type WHERE typeid = $3
                                                       ) 
                                 ORDER BY time ASC;`, networkID, siteID, typeID)
	case days != 0 && methodID == "":
		rows, err = db.Query(
			`SELECT format('%s,%s,%s', to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'), value, error) as csv FROM fits.observation 
                           WHERE 
                               sitepk = (
                                              SELECT DISTINCT ON (sitepk) sitepk from fits.site join fits.network using (networkpk) where siteid = $2 and networkid = $1 
                                            )
                               AND typepk = (
                                                        SELECT typepk FROM fits.type WHERE typeid = $3
                                                       ) 
                                AND time > (now() - interval '`+strconv.Itoa(days)+` days')
                  		ORDER BY time ASC;`, networkID, siteID, typeID)
	case days == 0 && methodID != "":
		rows, err = db.Query(
			`SELECT format('%s,%s,%s', to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'), value, error) as csv FROM fits.observation 
                           WHERE 
                               sitepk = (
                                              SELECT DISTINCT ON (sitepk) sitepk from fits.site join fits.network using (networkpk) where siteid = $2 and networkid = $1 
                                            )
                               AND typepk = (
                                                         SELECT typepk FROM fits.type WHERE typeid = $3
                                                       ) 
			AND methodpk = (
					SELECT methodpk FROM fits.method WHERE methodid = $4
				)
                                 ORDER BY time ASC;`, networkID, siteID, typeID, methodID)
	case days != 0 && methodID != "":
		rows, err = db.Query(
			`SELECT format('%s,%s,%s', to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'), value, error) as csv FROM fits.observation 
                           WHERE 
                               sitepk = (
                                              SELECT DISTINCT ON (sitepk) sitepk from fits.site join fits.network using (networkpk) where siteid = $2 and networkid = $1 
                                            )
                               AND typepk = (
                                                         SELECT typepk FROM fits.type WHERE typeid = $3
                                                       ) 
		AND methodpk = (
					SELECT methodpk FROM fits.method WHERE methodid = $4
				)
                                AND time > (now() - interval '`+strconv.Itoa(days)+` days')
                  		ORDER BY time ASC;`, networkID, siteID, typeID, methodID)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}
	defer rows.Close()

	// Use a buffer for reading the data from the DB.  Then if a there
	// is an error we can let the client know without sending
	// a partial data response.
	var b bytes.Buffer
	b.Write([]byte("date-time, " + typeID + " (" + unit + "), error (" + unit + ")"))
	b.Write(eol)
	for rows.Next() {
		err := rows.Scan(&d)
		if err != nil {
			web.ServiceUnavailable(w, r, err)
			return
		}
		b.Write([]byte(d))
		b.Write(eol)
	}
	rows.Close()

	if methodID != "" {
		w.Header().Set("Content-Disposition", `attachment; filename="FITS-`+networkID+`-`+siteID+`-`+typeID+`-`+methodID+`.csv"`)
	} else {
		w.Header().Set("Content-Disposition", `attachment; filename="FITS-`+networkID+`-`+siteID+`-`+typeID+`.csv"`)
	}

	w.Header().Set("Content-Type", web.V1CSV)
	web.OkBuf(w, r, &b)
}
コード例 #28
0
ファイル: plot_site.go プロジェクト: jmptrader/fits
func plotSite(w http.ResponseWriter, r *http.Request) {
	if err := plotSiteD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	var plotType string
	var s siteQ
	var t typeQ
	var start time.Time
	var days int
	var ymin, ymax float64
	var showMethod bool
	var stddev string
	var ok bool

	if plotType, ok = getPlotType(w, r); !ok {
		return
	}

	if showMethod, ok = getShowMethod(w, r); !ok {
		return
	}

	if stddev, ok = getStddev(w, r); !ok {
		return
	}

	if start, ok = getStart(w, r); !ok {
		return
	}

	if days, ok = getDays(w, r); !ok {
		return
	}

	if ymin, ymax, ok = getYRange(w, r); !ok {
		return
	}

	if t, ok = getType(w, r); !ok {
		return
	}

	if s, ok = getSite(w, r); !ok {
		return
	}

	var p plt

	switch {
	case start.IsZero() && days == 0:
		// do nothing - autorange on the data.
	case start.IsZero() && days > 0:
		n := time.Now().UTC()
		start = n.Add(time.Duration(days*-1) * time.Hour * 24)
		p.SetXAxis(start, n)
		days = 0 // add all data > than start by setting 0.  Allows for adding start end to URL.
	case !start.IsZero() && days > 0:
		p.SetXAxis(start, start.Add(time.Duration(days*1)*time.Hour*24))
	case !start.IsZero() && days == 0:
		web.BadRequest(w, r, "Invalid start specified without days")
		return
	}

	switch {
	case ymin == 0 && ymax == 0:
	case ymin == ymax:
		p.SetYRange(ymin)
	default:
		p.SetYAxis(ymin, ymax)
	}

	p.SetTitle(fmt.Sprintf("%s (%s) - %s", s.siteID, s.name, t.description))
	p.SetUnit(t.unit)
	p.SetYLabel(fmt.Sprintf("%s (%s)", t.name, t.unit))

	var err error

	switch showMethod {
	case false:
		err = p.addSeries(t, start, days, s)
	case true:
		err = p.addSeriesLabelMethod(t, start, days, s)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	if stddev == `pop` {
		err = p.setStddevPop(s, t, start, days)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := new(bytes.Buffer)

	switch plotType {
	case ``, `line`:
		err = ts.Line.Draw(p.Plot, b)
	case `scatter`:
		err = ts.Scatter.Draw(p.Plot, b)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Content-Type", "image/svg+xml")
	web.OkBuf(w, r, b)
}
コード例 #29
0
ファイル: spark.go プロジェクト: jmptrader/fits
func spark(w http.ResponseWriter, r *http.Request) {
	if err := sparkD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	var plotType string
	var s siteQ
	var t typeQ
	var days int
	var ymin, ymax float64
	var stddev string
	var label string
	var ok bool

	if plotType, ok = getPlotType(w, r); !ok {
		return
	}

	if stddev, ok = getStddev(w, r); !ok {
		return
	}

	if label, ok = getSparkLabel(w, r); !ok {
		return
	}

	if days, ok = getDays(w, r); !ok {
		return
	}

	if ymin, ymax, ok = getYRange(w, r); !ok {
		return
	}

	if t, ok = getType(w, r); !ok {
		return
	}

	if s, ok = getSite(w, r); !ok {
		return
	}

	var p plt
	var tmin time.Time

	if days > 0 {
		n := time.Now().UTC()
		tmin = n.Add(time.Duration(days*-1) * time.Hour * 24)
		p.SetXAxis(tmin, n)
		days = 0 // add all data > than tmin
	}

	switch {
	case ymin == 0 && ymax == 0:
	case ymin == ymax:
		p.SetYRange(ymin)
	default:
		p.SetYAxis(ymin, ymax)
	}

	p.SetUnit(t.unit)

	var err error

	if stddev == `pop` {
		err = p.setStddevPop(s, t, tmin, days)
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	err = p.addSeries(t, tmin, days, s)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b := new(bytes.Buffer)

	switch plotType {
	case ``, `line`:
		switch label {
		case ``, `all`:
			err = ts.SparkLineAll.Draw(p.Plot, b)
		case `latest`:
			err = ts.SparkLineLatest.Draw(p.Plot, b)
		case `none`:
			err = ts.SparkLineNone.Draw(p.Plot, b)
		}
	case `scatter`:
		switch label {
		case ``, `all`:
			err = ts.SparkScatterAll.Draw(p.Plot, b)
		case `latest`:
			err = ts.SparkScatterLatest.Draw(p.Plot, b)
		case `none`:
			err = ts.SparkScatterNone.Draw(p.Plot, b)
		}
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Content-Type", "image/svg+xml")
	web.OkBuf(w, r, b)
}
コード例 #30
0
ファイル: quake.go プロジェクト: nmacnz/geonet-rest
func quakes(w http.ResponseWriter, r *http.Request) {
	if err := quakesD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	number := v.Get("number")
	regionID := v.Get("regionID")
	intensity := v.Get("intensity")
	quality := strings.Split(v.Get("quality"), ",")

	if !numberRe.MatchString(number) {
		web.BadRequest(w, r, "Invalid query parameter number: "+number)
		return
	}

	if !intensityRe.MatchString(intensity) {
		web.BadRequest(w, r, "Invalid intensity: "+intensity)
		return
	}

	for _, q := range quality {
		if !qualityRe.MatchString(q) {
			web.BadRequest(w, r, "Invalid quality: "+q)
			return
		}
	}

	var d string
	err := db.QueryRow("select regionname FROM qrt.region where regionname = $1 AND groupname in ('region', 'north', 'south')", regionID).Scan(&d)
	if err == sql.ErrNoRows {
		web.BadRequest(w, r, "invalid quake regionID: "+regionID)
		return
	}
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	err = db.QueryRow(
		`SELECT row_to_json(fc)
                         FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features
                         FROM (SELECT 'Feature' as type,
                         ST_AsGeoJSON(q.origin_geom)::json as geometry,
                         row_to_json((SELECT l FROM
                         	(
                         		SELECT
                         		publicid AS "publicID",
                                to_char(origintime, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "time",
                                depth,
                                magnitude,
                                type,
                                agency,
                                locality,
                                intensity,
                                intensity_`+regionID+` as "regionIntensity",
                                quality,
                                to_char(updatetime, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "modificationTime"
                           ) as l
                         )) as properties FROM qrt.quakeinternal_v2 as q where maxmmi >= qrt.intensity_to_mmi($1)
                         AND quality in ('`+strings.Join(quality, `','`)+`')  AND ST_Contains((select geom from qrt.region where regionname = $3), ST_Shift_Longitude(origin_geom)) limit $2 ) as f ) as fc`, intensity, number, regionID).Scan(&d)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}
	b := []byte(d)
	web.Ok(w, r, &b)
}