Add sending messages to chats and groups
This commit is contained in:
parent
e192f2d8f9
commit
f3b9e91040
136
src/graphql.rs
136
src/graphql.rs
@ -6,6 +6,11 @@ use std::{
|
|||||||
collections::BTreeSet,
|
collections::BTreeSet,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
time::{
|
||||||
|
SystemTime,
|
||||||
|
SystemTimeError,
|
||||||
|
UNIX_EPOCH,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use juniper::{
|
use juniper::{
|
||||||
EmptySubscription,
|
EmptySubscription,
|
||||||
@ -149,13 +154,23 @@ async fn user_authentication(db: &SqlitePool, user: &uuid::adapter::Simple, pass
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn user_exists(db: &SqlitePool, user: &uuid::adapter::Simple) -> FieldResult<()> {
|
async fn user_exists(db: &SqlitePool, user: &uuid::adapter::Simple) -> FieldResult<()> {
|
||||||
if sqlx::query(
|
if sqlx::query(
|
||||||
format!(r#"SELECT id FROM users WHERE id = "{}""#, user).as_str()
|
format!(r#"SELECT id FROM users WHERE id = "{}""#, user).as_str()
|
||||||
).fetch_optional(db).await?.is_some() {
|
).fetch_optional(db).await?.is_some() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(format!(r#"user "{}" does not exist on this server"#, user).into())
|
Err(format!(r#"user "{}" does not exist on this server"#, user).into())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn chat_exists(db: &SqlitePool, chat: &uuid::adapter::Simple) -> FieldResult<()> {
|
||||||
|
if sqlx::query(
|
||||||
|
format!(r#"SELECT id FROM chat_index WHERE id = "{}""#, chat).as_str()
|
||||||
|
).fetch_optional(db).await?.is_some() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!(r#"chat "{}" does not exist on this server"#, chat).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -390,6 +405,79 @@ pub struct GroupChat {
|
|||||||
users: Vec<ID>,
|
users: Vec<ID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, GraphQLInputObject, Type)]
|
||||||
|
pub struct MessageInput {
|
||||||
|
msg_type: MsgType,
|
||||||
|
content: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageInput {
|
||||||
|
pub fn try_into_message(self, user: &uuid::adapter::Simple) -> Result<Message, SystemTimeError> {
|
||||||
|
let sender: ID = user.to_string().into();
|
||||||
|
|
||||||
|
Ok(Message {
|
||||||
|
id: Uuid::new_v4().to_simple().to_string().into(),
|
||||||
|
timestamp: SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)?
|
||||||
|
.as_millis(),
|
||||||
|
sender: sender.clone(),
|
||||||
|
msg_type: self.msg_type,
|
||||||
|
content: self.content,
|
||||||
|
hide_for: None,
|
||||||
|
seen_by: vec![sender],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Type)]
|
||||||
|
pub struct Message {
|
||||||
|
id: ID,
|
||||||
|
timestamp: u128,
|
||||||
|
sender: ID,
|
||||||
|
msg_type: MsgType,
|
||||||
|
content: Option<String>,
|
||||||
|
hide_for: Option<Vec<ID>>,
|
||||||
|
seen_by: Vec<ID>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Message {
|
||||||
|
fn id(&self) -> &ID {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestamp(&self) -> String {
|
||||||
|
self.timestamp.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sender(&self) -> &ID {
|
||||||
|
&self.sender
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msg_type(&self) -> MsgType {
|
||||||
|
self.msg_type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn content(&self) -> Option<&str> {
|
||||||
|
self.content.as_ref().map(|s| &**s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_for(&self) -> Option<&[ID]> {
|
||||||
|
self.hide_for.as_ref().map(|v| &v[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seen_by(&self) -> &[ID] {
|
||||||
|
&self.seen_by
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, GraphQLEnum, Type)]
|
||||||
|
#[repr(u8)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum MsgType {
|
||||||
|
Text = 0,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Query;
|
pub struct Query;
|
||||||
|
|
||||||
@ -668,6 +756,40 @@ impl Mutation {
|
|||||||
|
|
||||||
Ok(group_chat_uuid.to_simple().to_string().into())
|
Ok(group_chat_uuid.to_simple().to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn sendMessage(context: &Context, user: ID, password_hash: String, chat: ID, msg: MessageInput) -> FieldResult<ID> {
|
||||||
|
let user = id_to_uuid(&user)?.to_simple();
|
||||||
|
user_authentication(&context.db, &user, &password_hash).await?;
|
||||||
|
|
||||||
|
let msg: Message = msg.try_into_message(&user)?;
|
||||||
|
let msg_id = id_to_uuid(&msg.id)?.to_simple();
|
||||||
|
|
||||||
|
let chat = id_to_uuid(&chat)?.to_simple();
|
||||||
|
chat_exists(&context.db, &chat).await?;
|
||||||
|
|
||||||
|
if msg.timestamp > i64::MAX as u128 {
|
||||||
|
eprintln!("WARNING: Timestamp value is greater than sqlite can handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlx::query(format!(
|
||||||
|
r#"INSERT INTO msgdata_{} VALUES ("{}", {}, "{}", {}, {}, {}, "{}")"#,
|
||||||
|
chat,
|
||||||
|
&msg_id,
|
||||||
|
msg.timestamp,
|
||||||
|
user,
|
||||||
|
msg.msg_type as u8,
|
||||||
|
msg.content
|
||||||
|
.map(|c| format!(r#""{}""#, c))
|
||||||
|
.unwrap_or("NULL".to_string()),
|
||||||
|
msg.hide_for
|
||||||
|
.map(format_array_for_sql)
|
||||||
|
.map(|a| format!(r#""{}""#, a))
|
||||||
|
.unwrap_or("NULL".to_string()),
|
||||||
|
format_array_for_sql(msg.seen_by),
|
||||||
|
).as_str()).execute(&context.db).await?;
|
||||||
|
|
||||||
|
Ok(msg_id.to_string().into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Schema<'root_node> = RootNode<'root_node, Query, Mutation, EmptySubscription<Context>>;
|
pub type Schema<'root_node> = RootNode<'root_node, Query, Mutation, EmptySubscription<Context>>;
|
||||||
|
17
test-api.sh
17
test-api.sh
@ -1,13 +1,20 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
echo Create users @a, @b, and @c:
|
echo Create users @a, @b, and @c:
|
||||||
userIDs=$(curl "localhost:8080/graphql" -X POST -H "content-type: application/json" --data '{"query":"mutation addUsers($a: NewUser!, $b: NewUser!, $c: NewUser!) {\n a: newUser(newUser: $a)\n b: newUser(newUser: $b)\n c: newUser(newUser: $c)\n}","variables":{"a":{"userName":"@a","passwordHash":"1234567890"},"b":{"userName":"@b","passwordHash":"1234567890"},"c":{"userName":"@c","passwordHash":"1234567890"}},"operationName":"addUsers"}' | jq .data)
|
userIDs=$(curl "localhost:8081/graphql" -X POST -H "content-type: application/json" --data '{"query":"mutation addUsers($a: NewUser!, $b: NewUser!, $c: NewUser!) {\n a: newUser(newUser: $a)\n b: newUser(newUser: $b)\n c: newUser(newUser: $c)\n}","variables":{"a":{"userName":"@a","passwordHash":"1234567890"},"b":{"userName":"@b","passwordHash":"1234567890"},"c":{"userName":"@c","passwordHash":"1234567890"}},"operationName":"addUsers"}' | jq .data)
|
||||||
echo "$userIDs" | jq .
|
echo "$userIDs" | jq .
|
||||||
a=$(echo "$userIDs" | jq -r .a)
|
a=$(echo "$userIDs" | jq -r .a)
|
||||||
b=$(echo "$userIDs" | jq -r .b)
|
b=$(echo "$userIDs" | jq -r .b)
|
||||||
c=$(echo "$userIDs" | jq -r .c)
|
c=$(echo "$userIDs" | jq -r .c)
|
||||||
|
|
||||||
echo Create chats between @a and @b, @a and @c, and group chats between @a, @b, and @c:
|
echo -e \nCreate chats between @a and @b, @a and @c, and group chats between @a, @b, and @c:
|
||||||
curl "localhost:8080/graphql" -X POST -H "content-type: application/json" --data "{\"query\":\"mutation createChat(\$a: ID!, \$b: ID!, \$c: ID!, \$pwHash: String!) {\n ab: newChat(user: \$a, passwordHash: \$pwHash, with: \$b)\n ac: newChat(user: \$a, passwordHash: \$pwHash, with: \$c)\n abc: newGroupChat(user: \$a, passwordHash: \$pwHash, with: [\$b, \$c], title: \\\"ABC\\\")\n}\",\"variables\":{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"b\":\"$b\",\"c\":\"$c\"},\"operationName\":\"createChat\"}" | jq .data
|
curl "localhost:8081/graphql" -X POST -H "content-type: application/json" --data "{\"query\":\"mutation createChat(\$a: ID!, \$b: ID!, \$c: ID!, \$pwHash: String!) {\n ab: newChat(user: \$a, passwordHash: \$pwHash, with: \$b)\n ac: newChat(user: \$a, passwordHash: \$pwHash, with: \$c)\n abc: newGroupChat(user: \$a, passwordHash: \$pwHash, with: [\$b, \$c], title: \\\"ABC\\\")\n}\",\"variables\":{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"b\":\"$b\",\"c\":\"$c\"},\"operationName\":\"createChat\"}" | jq .data
|
||||||
|
|
||||||
echo List all users\' chats:
|
echo -e \nList all users\' chats:
|
||||||
curl "localhost:8080/graphql" -X POST -H "content-type: application/json" --data "{\"query\":\"query listChats(\$a: ID!, \$b: ID!, \$c: ID!, \$pwHash: String!) {\n aChats: chats(user: \$a, passwordHash: \$pwHash) {\n id\n users\n }\n aGroupChats: groupChats(user: \$a, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n bChats: chats(user: \$b, passwordHash: \$pwHash) {\n id\n users\n }\n bGroupChats: groupChats(user: \$b, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n cChats: chats(user: \$c, passwordHash: \$pwHash) {\n id\n users\n }\n cGroupChats: groupChats(user: \$c, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n}\",\"variables\":{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"b\":\"$b\",\"c\":\"$c\"},\"operationName\":\"listChats\"}" | jq .data
|
chatIDs=$(curl "localhost:8081/graphql" -X POST -H "content-type: application/json" --data "{\"query\":\"query listChats(\$a: ID!, \$b: ID!, \$c: ID!, \$pwHash: String!) {\n aChats: chats(user: \$a, passwordHash: \$pwHash) {\n id\n users\n }\n aGroupChats: groupChats(user: \$a, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n bChats: chats(user: \$b, passwordHash: \$pwHash) {\n id\n users\n }\n bGroupChats: groupChats(user: \$b, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n cChats: chats(user: \$c, passwordHash: \$pwHash) {\n id\n users\n }\n cGroupChats: groupChats(user: \$c, passwordHash: \$pwHash) {\n id\n title\n description\n users\n }\n}\",\"variables\":{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"b\":\"$b\",\"c\":\"$c\"},\"operationName\":\"listChats\"}" | jq .data)
|
||||||
|
echo "$chatIDs" | jq .
|
||||||
|
ab=$(echo "$chatIDs" | jq -r .aChats[0].id)
|
||||||
|
abc=$(echo "$chatIDs" | jq -r .aGroupChats[0].id)
|
||||||
|
|
||||||
|
echo -e \nSend a private/group message:
|
||||||
|
#echo "{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"bChat\":\"$ab\",\"abc\":\"$abc\",\"msg\":{\"msgType\":\"TEXT\",\"content\":\"Test\"}}" | jq .
|
||||||
|
curl "localhost:8081/graphql" -X POST -H "content-type: application/json" --data "{\"query\":\"mutation sendMessages(\$a: ID!, \$pwHash: String!, \$bChat: ID!, \$abc: ID!, \$msg: MessageInput!) {\n chat: sendMessage(user: \$a, passwordHash: \$pwHash, chat: \$bChat, msg: \$msg)\n group: sendMessage(user: \$a, passwordHash: \$pwHash, chat: \$abc, msg: \$msg)\n}\",\"variables\":{\"pwHash\":\"1234567890\",\"a\":\"$a\",\"bChat\":\"$ab\",\"abc\":\"$abc\",\"msg\":{\"msgType\":\"TEXT\",\"content\":\"Test\"}},\"operationName\":\"sendMessages\"}" | jq .
|
Loading…
Reference in New Issue
Block a user