From 3c7852271a1fefb836e3f10a52763ea6b436d278 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Feb 2021 14:50:23 +0000 Subject: [PATCH] Add temporary typing indicator impl. --- src/database/entities/user.rs | 35 +++++++++++++++++++++++++++++- src/notifications/events.rs | 14 ++++++++++++ src/notifications/websocket.rs | 39 ++++++++++++++++++++++++++++++++-- src/routes/onboard/complete.rs | 27 +++-------------------- 4 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/database/entities/user.rs b/src/database/entities/user.rs index ff69e933..dc703226 100644 --- a/src/database/entities/user.rs +++ b/src/database/entities/user.rs @@ -1,6 +1,11 @@ +use mongodb::bson::doc; use serde::{Deserialize, Serialize}; +use mongodb::options::{Collation, FindOneOptions}; -use crate::{database::permissions::user::UserPermissions, notifications::websocket::is_online}; +use crate::database::*; +use crate::util::result::{Error, Result}; +use crate::notifications::websocket::is_online; +use crate::database::permissions::user::UserPermissions; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum RelationshipStatus { @@ -62,4 +67,32 @@ impl User { self } + + /// Utility function for checking claimed usernames. + pub async fn is_username_taken(username: &str) -> Result { + if username == "revolt" && username == "admin" { + return Ok(true) + } + + if get_collection("users") + .find_one( + doc! { + "username": username + }, + FindOneOptions::builder() + .collation(Collation::builder().locale("en").strength(2).build()) + .build(), + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "find_one", + with: "user", + })? + .is_some() + { + Ok(true) + } else { + Ok(false) + } + } } diff --git a/src/notifications/events.rs b/src/notifications/events.rs index b21ffcac..de643e72 100644 --- a/src/notifications/events.rs +++ b/src/notifications/events.rs @@ -26,6 +26,12 @@ pub enum WebSocketError { #[serde(tag = "type")] pub enum ServerboundNotification { Authenticate(Session), + BeginTyping { + channel: String + }, + EndTyping { + channel: String + } } #[derive(Serialize, Deserialize, Debug)] @@ -63,6 +69,14 @@ pub enum ClientboundNotification { ChannelDelete { id: String, }, + ChannelStartTyping { + id: String, + user: String + }, + ChannelStopTyping { + id: String, + user: String + }, UserRelationship { id: String, diff --git a/src/notifications/websocket.rs b/src/notifications/websocket.rs index 841c4375..eaceedf9 100644 --- a/src/notifications/websocket.rs +++ b/src/notifications/websocket.rs @@ -71,8 +71,6 @@ async fn accept(stream: TcpStream) { let fwd = rx.map(Ok).forward(write); let incoming = read.try_for_each(async move |msg| { let mutex = mutex_generator(); - //dbg!(&mutex.lock().unwrap()); - if let Message::Text(text) = msg { if let Ok(notification) = serde_json::from_str::(&text) { match notification { @@ -161,6 +159,43 @@ async fn accept(stream: TcpStream) { )); } } + // ! TEMP: verify user part of channel + // ! Could just run permission check here. + ServerboundNotification::BeginTyping { channel } => { + if mutex.lock().unwrap().is_some() { + ClientboundNotification::ChannelStartTyping { + id: channel.clone(), + // lol + user: mutex.lock().as_ref().unwrap().as_ref().unwrap().user_id.clone() + } + .publish(channel) + .await + .ok(); + } else { + send(ClientboundNotification::Error( + WebSocketError::AlreadyAuthenticated, + )); + + return Ok(()); + } + } + ServerboundNotification::EndTyping { channel } => { + if mutex.lock().unwrap().is_some() { + ClientboundNotification::ChannelStopTyping { + id: channel.clone(), + user: mutex.lock().as_ref().unwrap().as_ref().unwrap().user_id.clone() + } + .publish(channel) + .await + .ok(); + } else { + send(ClientboundNotification::Error( + WebSocketError::AlreadyAuthenticated, + )); + + return Ok(()); + } + } } } } diff --git a/src/routes/onboard/complete.rs b/src/routes/onboard/complete.rs index a35e1b1d..68583efe 100644 --- a/src/routes/onboard/complete.rs +++ b/src/routes/onboard/complete.rs @@ -2,7 +2,6 @@ use crate::database::*; use crate::util::result::{Error, Result}; use mongodb::bson::doc; -use mongodb::options::{Collation, FindOneOptions}; use rauth::auth::Session; use regex::Regex; use rocket_contrib::json::Json; @@ -28,31 +27,11 @@ pub async fn req(session: Session, user: Option, data: Json) -> Resu data.validate() .map_err(|error| Error::FailedValidation { error })?; - if data.username == "revolt" { - Err(Error::UsernameTaken)? + if User::is_username_taken(&data.username).await? { + return Err(Error::UsernameTaken) } - let col = get_collection("users"); - if col - .find_one( - doc! { - "username": &data.username - }, - FindOneOptions::builder() - .collation(Collation::builder().locale("en").strength(2).build()) - .build(), - ) - .await - .map_err(|_| Error::DatabaseError { - operation: "find_one", - with: "user", - })? - .is_some() - { - Err(Error::UsernameTaken)? - } - - col.insert_one( + get_collection("users").insert_one( doc! { "_id": session.user_id, "username": &data.username