Add sending messages to chats and groups

This commit is contained in:
2021-12-12 22:52:11 +01:00
parent e192f2d8f9
commit f3b9e91040
2 changed files with 141 additions and 12 deletions

View File

@@ -6,6 +6,11 @@ use std::{
collections::BTreeSet,
fmt::Display,
str::FromStr,
time::{
SystemTime,
SystemTimeError,
UNIX_EPOCH,
},
};
use juniper::{
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<()> {
if sqlx::query(
format!(r#"SELECT id FROM users WHERE id = "{}""#, user).as_str()
).fetch_optional(db).await?.is_some() {
Ok(())
} else {
Err(format!(r#"user "{}" does not exist on this server"#, user).into())
}
if sqlx::query(
format!(r#"SELECT id FROM users WHERE id = "{}""#, user).as_str()
).fetch_optional(db).await?.is_some() {
Ok(())
} else {
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)]
@@ -390,6 +405,79 @@ pub struct GroupChat {
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)]
pub struct Query;
@@ -668,6 +756,40 @@ impl Mutation {
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>>;