diff options
Diffstat (limited to 'src/graphql/types')
| -rw-r--r-- | src/graphql/types/alert.rs | 125 | ||||
| -rw-r--r-- | src/graphql/types/mod.rs | 1 | ||||
| -rw-r--r-- | src/graphql/types/position.rs | 31 |
3 files changed, 128 insertions, 29 deletions
diff --git a/src/graphql/types/alert.rs b/src/graphql/types/alert.rs new file mode 100644 index 0000000..006e9ae --- /dev/null +++ b/src/graphql/types/alert.rs @@ -0,0 +1,125 @@ +use crate::{dates::GraphQLDate, graphql::types::jwt::Authentication, state::AppState}; +use async_graphql::{Context, Enum, InputObject, SimpleObject}; +use chrono::Utc; +use serde::{Deserialize, Serialize}; +use std::error::Error; +use tokio_postgres::types::{to_sql_checked, FromSql, IsNull, ToSql, Type}; + +#[derive(Enum, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +/// Enumeration which refers to the level of alert +pub enum LevelAlert { + // User in the AREA + One, + + // User in the AREA OR < 1km distance + Two, + + // User in the AREA OR < 2km distance + Three, +} + +impl<'a> FromSql<'a> for LevelAlert { + fn from_sql(_ty: &Type, raw: &'a [u8]) -> Result<LevelAlert, Box<dyn Error + Sync + Send>> { + match std::str::from_utf8(raw)? { + "One" => Ok(LevelAlert::One), + "Two" => Ok(LevelAlert::Two), + "Three" => Ok(LevelAlert::Three), + other => Err(format!("Unknown variant: {}", other).into()), + } + } + + fn accepts(ty: &Type) -> bool { + ty.name() == "level_alert" + } +} + +impl ToSql for LevelAlert { + fn to_sql( + &self, + _ty: &Type, + out: &mut bytes::BytesMut, + ) -> Result<IsNull, Box<dyn Error + Sync + Send>> { + let value = match *self { + LevelAlert::One => "One", + LevelAlert::Two => "Two", + LevelAlert::Three => "Three", + }; + out.extend_from_slice(value.as_bytes()); + Ok(IsNull::No) + } + + fn accepts(ty: &Type) -> bool { + ty.name() == "level_alert" + } + + to_sql_checked!(); +} + +#[derive(SimpleObject, Clone, Debug, Serialize, Deserialize)] +/// Alert struct +pub struct Alert { + pub id: i32, + pub user_id: i32, + pub created_at: GraphQLDate, + pub area: String, + pub level: LevelAlert, + pub reached_users: i32, +} + +#[derive(InputObject)] +pub struct Point { + pub latitude: f64, + pub longitude: f64, +} + +#[derive(InputObject)] +/// Alert input struct +pub struct AlertInput { + pub points: Vec<Point>, + pub level: LevelAlert, +} + +/// Get alerts from the database +pub async fn get_alerts<'ctx>( + ctx: &Context<'ctx>, + + // Optional limit results + limit: Option<i64>, + + // Optional offset results. It should be used with limit field. + offset: Option<i64>, +) -> Result<Option<Vec<Alert>>, String> { + let state = ctx.data::<AppState>().expect("Can't connect to db"); + let client = &*state.client; + let auth: &Authentication = ctx.data().unwrap(); + match auth { + Authentication::NotLogged => Err("Unauthorized".to_string()), + Authentication::Logged(_) => { + let rows = client + .query( + "SELECT id, user_id, created_at, ST_AsText(area) as area, level, reached_users + FROM alerts + ORDER BY id DESC + LIMIT $1 + OFFSET $2", + &[&limit.unwrap_or(20), &offset.unwrap_or(0)], + ) + .await + .unwrap(); + + let positions: Vec<Alert> = rows + .iter() + .map(|row| Alert { + id: row.get("id"), + user_id: row.get("user_id"), + created_at: GraphQLDate(Utc::now()), + area: row.get("area"), + level: row.get("level"), + reached_users: row.get("reached_users"), + }) + .collect(); + + Ok(Some(positions)) + } + } +} diff --git a/src/graphql/types/mod.rs b/src/graphql/types/mod.rs index a77cf8c..d0f8ead 100644 --- a/src/graphql/types/mod.rs +++ b/src/graphql/types/mod.rs @@ -1,3 +1,4 @@ +pub mod alert; pub mod jwt; pub mod position; pub mod user; diff --git a/src/graphql/types/position.rs b/src/graphql/types/position.rs index 8610fcb..a9236a6 100644 --- a/src/graphql/types/position.rs +++ b/src/graphql/types/position.rs @@ -1,5 +1,5 @@ use crate::{dates::GraphQLDate, graphql::types::jwt::Authentication, state::AppState}; -use async_graphql::{Context, Enum, InputObject, Object}; +use async_graphql::{Context, Enum, InputObject, SimpleObject}; use chrono::Utc; use serde::{Deserialize, Serialize}; use std::error::Error; @@ -67,7 +67,7 @@ impl ToSql for MovingActivity { to_sql_checked!(); } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(SimpleObject, Clone, Debug, Serialize, Deserialize)] /// Position struct pub struct Position { pub id: i32, @@ -86,33 +86,6 @@ pub struct PositionInput { pub moving_activity: MovingActivity, } -#[Object] -impl Position { - async fn id(&self) -> i32 { - self.id - } - - async fn user_id(&self) -> i32 { - self.user_id - } - - async fn created_at(&self) -> GraphQLDate { - self.created_at.clone() - } - - async fn latitude(&self) -> f64 { - self.latitude - } - - async fn longitude(&self) -> f64 { - self.longitude - } - - async fn moving_activity(&self) -> MovingActivity { - self.moving_activity - } -} - /// Get positions from the database pub async fn get_positions<'ctx>( ctx: &Context<'ctx>, |
