Mercurial > lbo > hg > geohub
changeset 48:6ee4923958f0
Allow for attaching notes to points.
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Thu, 03 Dec 2020 21:56:22 +0100 |
parents | c3812802146c |
children | 27b4391e7df8 |
files | pgsql_schema.sql src/db.rs src/main.rs src/types.rs |
diffstat | 4 files changed, 68 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/pgsql_schema.sql Thu Dec 03 17:44:36 2020 +0100 +++ b/pgsql_schema.sql Thu Dec 03 21:56:22 2020 +0100 @@ -35,6 +35,7 @@ t timestamp with time zone not null, ele double precision secret bytea, + note text );
--- a/src/db.rs Thu Dec 03 17:44:36 2020 +0100 +++ b/src/db.rs Thu Dec 03 21:56:22 2020 +0100 @@ -21,16 +21,31 @@ ) -> Result<types::GeoJSON, postgres::Error> { let mut returnable = types::GeoJSON::new(); let stmt = self.0.prepare_cached( - r"SELECT id, t, lat, long, spd, ele FROM geohub.geodata + r"SELECT id, t, lat, long, spd, ele, note FROM geohub.geodata WHERE (client = $1) and (t between $2 and $3) AND (secret = public.digest($4, 'sha256') or secret is null) AND (id > $5) ORDER BY t ASC LIMIT $6").unwrap(); // Must succeed. let rows = stmt.query(&[&name, &from_ts, &to_ts, &secret, &last.unwrap_or(0), &limit])?; returnable.reserve_features(rows.len()); for row in rows.iter() { - let (id, ts, lat, long, spd, ele) = - (row.get(0), row.get(1), row.get(2), row.get(3), row.get(4), row.get(5)); - returnable.push_feature(types::geofeature_from_row(id, ts, lat, long, spd, ele)); + let (id, ts, lat, long, spd, ele, note) = ( + row.get(0), + row.get(1), + row.get(2), + row.get(3), + row.get(4), + row.get(5), + row.get(6), + ); + let point = types::GeoPoint { + lat: lat, + long: long, + spd: spd, + ele: ele, + note: note, + time: ts, + }; + returnable.push_feature(types::geofeature_from_point(id, point)); } Ok(returnable) } @@ -41,8 +56,12 @@ secret: &Option<String>, point: &types::GeoPoint, ) -> Result<(), postgres::Error> { - let stmt = self.0.prepare_cached("INSERT INTO geohub.geodata (client, lat, long, spd, t, ele, secret) VALUES ($1, $2, $3, $4, $5, $6, public.digest($7, 'sha256'))").unwrap(); - let channel = format!("NOTIFY {}, '{}'", ids::channel_name(name, secret.as_ref().unwrap_or(&"".into()).as_str()), name); + let stmt = self.0.prepare_cached("INSERT INTO geohub.geodata (client, lat, long, spd, t, ele, secret, note) VALUES ($1, $2, $3, $4, $5, $6, public.digest($7, 'sha256'), $8)").unwrap(); + let channel = format!( + "NOTIFY {}, '{}'", + ids::channel_name(name, secret.as_ref().unwrap_or(&"".into()).as_str()), + name + ); let notify = self.0.prepare_cached(channel.as_str()).unwrap(); stmt.execute(&[ &name, @@ -52,6 +71,7 @@ &point.time, &point.ele, &secret, + &point.note, ]) .unwrap(); notify.execute(&[]).unwrap(); @@ -68,7 +88,7 @@ ) -> Option<(types::GeoJSON, i32)> { let mut returnable = types::GeoJSON::new(); let check_for_new = self.0.prepare_cached( - r"SELECT id, t, lat, long, spd, ele FROM geohub.geodata + r"SELECT id, t, lat, long, spd, ele, note FROM geohub.geodata WHERE (client = $1) and (id > $2) AND (secret = public.digest($3, 'sha256') or secret is null) ORDER BY id DESC LIMIT $4").unwrap(); // Must succeed. @@ -84,15 +104,24 @@ let mut last = 0; for row in rows.iter() { - let (id, ts, lat, long, spd, ele) = ( + let (id, ts, lat, long, spd, ele, note) = ( row.get(0), row.get(1), row.get(2), row.get(3), row.get(4), row.get(5), + row.get(6), ); - returnable.push_feature(types::geofeature_from_row(Some(id), ts, lat, long, spd, ele)); + let point = types::GeoPoint { + time: ts, + lat: lat, + long: long, + spd: spd, + ele: ele, + note: note, + }; + returnable.push_feature(types::geofeature_from_point(Some(id), point)); if id > last { last = id; }
--- a/src/main.rs Thu Dec 03 17:44:36 2020 +0100 +++ b/src/main.rs Thu Dec 03 21:56:22 2020 +0100 @@ -94,7 +94,10 @@ /// time is like 2020-11-30T20:12:36.444Z (ISO 8601). By default, server time is set. /// secret can be used to protect points. -#[rocket::post("/geo/<name>/log?<lat>&<longitude>&<time>&<s>&<ele>&<secret>")] +#[rocket::post( + "/geo/<name>/log?<lat>&<longitude>&<time>&<s>&<ele>&<secret>", + data = "<note>" +)] fn log( db: db::DBConn, name: String, @@ -104,6 +107,7 @@ time: Option<String>, s: Option<f64>, ele: Option<f64>, + note: Option<String>, ) -> http::GeoHubResponse { let db = db::DBQuery(&db.0); // Check that secret and client name are legal. @@ -117,12 +121,25 @@ if let Some(time) = time { ts = util::flexible_timestamp_parse(time).unwrap_or(ts); } + + // Only store a note if one was attached. + let note = if let Some(note) = note { + if note.is_empty() { + None + } else { + Some(note) + } + } else { + note + }; + let point = types::GeoPoint { lat: lat, long: longitude, time: ts, spd: s, ele: ele, + note: note, }; if let Err(e) = db.log_geopoint(name.as_str(), &secret, &point) { return http::server_error(e.to_string());
--- a/src/types.rs Thu Dec 03 17:44:36 2020 +0100 +++ b/src/types.rs Thu Dec 03 21:56:22 2020 +0100 @@ -6,6 +6,7 @@ pub spd: Option<f64>, pub ele: Option<f64>, pub time: chrono::DateTime<chrono::Utc>, + pub note: Option<String>, } #[derive(serde::Serialize, Debug)] @@ -35,14 +36,17 @@ time: chrono::DateTime<chrono::Utc>, altitude: Option<f64>, speed: Option<f64>, + /// The unique ID of the point. id: Option<i32>, + /// An arbitrary note attached by the logging client. + note: Option<String>, } #[derive(serde::Serialize, Debug, Clone)] pub struct GeoGeometry { #[serde(rename = "type")] typ: String, // always "Point" - coordinates: Vec<f64>, // always [long, lat] + coordinates: (f64, f64), // always [long, lat] } #[derive(serde::Serialize, Debug, Clone)] @@ -75,25 +79,19 @@ } } -pub fn geofeature_from_row( - id: Option<i32>, - ts: chrono::DateTime<chrono::Utc>, - lat: Option<f64>, - long: Option<f64>, - spd: Option<f64>, - ele: Option<f64>, -) -> GeoFeature { +pub fn geofeature_from_point(id: Option<i32>, point: GeoPoint) -> GeoFeature { GeoFeature { typ: "Feature".into(), properties: GeoProperties { id: id, - time: ts, - altitude: ele, - speed: spd, + time: point.time, + altitude: point.ele, + speed: point.spd, + note: point.note, }, geometry: GeoGeometry { typ: "Point".into(), - coordinates: vec![long.unwrap_or(0.), lat.unwrap_or(0.)], + coordinates: (point.long, point.lat), }, } }