summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2024-09-05 11:25:29 +0200
committerSanto Cariotti <santo@dcariotti.me>2024-09-05 11:25:29 +0200
commit7e9dbd60f55f02ab065c764f8230aabaa6778eed (patch)
tree53d41bb27dbc3cf6e3c17ae99742029ab554ce53
parent58ff30ec66b5fd94c98cd0dfe441d6968af35ff2 (diff)
Keep a device token for the user notification
-rw-r--r--schema/init.sql1
-rw-r--r--src/graphql/mutation.rs46
-rw-r--r--src/graphql/types/user.rs29
3 files changed, 67 insertions, 9 deletions
diff --git a/schema/init.sql b/schema/init.sql
index 7c1c5b8..9a6abee 100644
--- a/schema/init.sql
+++ b/schema/init.sql
@@ -4,6 +4,7 @@ CREATE TABLE users(
password text NOT NULL,
name text NULL,
address text NULL,
+ notification_token text NULL,
is_admin boolean default false,
PRIMARY KEY (id)
);
diff --git a/src/graphql/mutation.rs b/src/graphql/mutation.rs
index a389a04..b5de3fb 100644
--- a/src/graphql/mutation.rs
+++ b/src/graphql/mutation.rs
@@ -3,7 +3,7 @@ use crate::{
alert,
jwt::{self, Authentication},
position,
- user::find_user,
+ user::{self, find_user},
},
state::AppState,
};
@@ -58,6 +58,50 @@ impl Mutation {
}
}
+ /// Make GraphQL call to register a notification device token for the user.
+ ///
+ /// Example:
+ /// ```text
+ /// curl -X POST http://localhost:8000/graphql \
+ /// -H "Content-Type: application/json" \
+ /// -d '{
+ /// "query": "mutation RegisterDevice($input: RegisterNotificationToken!) { registerDevice(input: $input) { id name email } }",
+ /// "variables": {
+ /// "input": {
+ /// "token": "***",
+ /// }
+ /// }
+ /// }'
+ /// ```
+ async fn register_device<'ctx>(
+ &self,
+ ctx: &Context<'ctx>,
+ input: user::RegisterNotificationToken,
+ ) -> FieldResult<user::User> {
+ 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(Error::new("Can't find the owner")),
+ Authentication::Logged(claims) => {
+ let user = find_user(client, claims.user_id)
+ .await
+ .expect("Should not be here");
+
+ client
+ .query(
+ "UPDATE users SET notification_token = $1 WHERE id = $2",
+ &[&input.token, &claims.user_id],
+ )
+ .await
+ .unwrap();
+
+ Ok(user)
+ }
+ }
+ }
+
/// Make GraphQL request to create new position to track
///
/// Example:
diff --git a/src/graphql/types/user.rs b/src/graphql/types/user.rs
index b185a16..09404ec 100644
--- a/src/graphql/types/user.rs
+++ b/src/graphql/types/user.rs
@@ -1,5 +1,5 @@
use crate::{errors::AppError, state::AppState};
-use async_graphql::{Context, Object};
+use async_graphql::{Context, InputObject, Object};
use serde::{Deserialize, Serialize};
use tokio_postgres::Client;
@@ -13,6 +13,7 @@ pub struct User {
pub password: String,
pub name: Option<String>,
pub address: Option<String>,
+ pub notification_token: Option<String>,
pub is_admin: bool,
}
@@ -38,11 +39,20 @@ impl User {
self.address.clone().unwrap_or(String::default())
}
+ async fn notification_token(&self) -> String {
+ String::from("******")
+ }
+
async fn is_admin(&self) -> bool {
self.is_admin
}
}
+#[derive(InputObject, Debug)]
+pub struct RegisterNotificationToken {
+ pub token: String,
+}
+
/// Get users from the database
pub async fn get_users<'ctx>(
ctx: &Context<'ctx>,
@@ -68,7 +78,7 @@ pub async fn get_users<'ctx>(
let rows = client
.query(
- "SELECT id, email, password, name, address, is_admin FROM users LIMIT $1 OFFSET $2",
+ "SELECT id, email, name, address, is_admin FROM users LIMIT $1 OFFSET $2",
&[&limit.unwrap_or(20), &offset.unwrap_or(0)],
)
.await
@@ -79,9 +89,10 @@ pub async fn get_users<'ctx>(
.map(|row| User {
id: row.get("id"),
email: row.get("email"),
- password: row.get("password"),
+ password: String::new(),
name: row.get("name"),
address: row.get("address"),
+ notification_token: None,
is_admin: row.get("is_admin"),
})
.collect();
@@ -107,7 +118,7 @@ pub async fn get_user_by_id<'ctx>(ctx: &Context<'ctx>, id: i32) -> Result<User,
if claim_user.is_admin {
rows = client
.query(
- "SELECT id, email, password, name, address, is_admin FROM users
+ "SELECT id, email, name, address, is_admin FROM users
WHERE id = $1",
&[&id],
)
@@ -118,7 +129,7 @@ pub async fn get_user_by_id<'ctx>(ctx: &Context<'ctx>, id: i32) -> Result<User,
} else {
rows = client
.query(
- "SELECT id, email, password, name, address, is_admin FROM users
+ "SELECT id, email, name, address, is_admin FROM users
WHERE id = $1",
&[&claims.user_id],
)
@@ -131,9 +142,10 @@ pub async fn get_user_by_id<'ctx>(ctx: &Context<'ctx>, id: i32) -> Result<User,
.map(|row| User {
id: row.get("id"),
email: row.get("email"),
- password: row.get("password"),
+ password: String::new(),
name: row.get("name"),
address: row.get("address"),
+ notification_token: None,
is_admin: row.get("is_admin"),
})
.collect();
@@ -151,7 +163,7 @@ pub async fn get_user_by_id<'ctx>(ctx: &Context<'ctx>, id: i32) -> Result<User,
pub async fn find_user(client: &Client, id: i32) -> Result<User, AppError> {
let rows = client
.query(
- "SELECT id, email, password, name, address, is_admin FROM users WHERE id = $1",
+ "SELECT id, email, name, address, is_admin FROM users WHERE id = $1",
&[&id],
)
.await
@@ -162,9 +174,10 @@ pub async fn find_user(client: &Client, id: i32) -> Result<User, AppError> {
.map(|row| User {
id: row.get("id"),
email: row.get("email"),
- password: row.get("password"),
+ password: String::new(),
name: row.get("name"),
address: row.get("address"),
+ notification_token: None,
is_admin: row.get("is_admin"),
})
.collect();