From 7728768539dd502b3124527f6fb61d1b9f30cf51 Mon Sep 17 00:00:00 2001
From: Paul Makles <paulmakles@gmail.com>
Date: Thu, 31 Dec 2020 14:59:26 +0000
Subject: [PATCH] Ready payload on websocket, add friend by username + avatars.

---
 .gitignore                     |  1 +
 Cargo.lock                     |  5 ++--
 Cargo.toml                     |  3 ++-
 Dockerfile                     |  2 +-
 src/database/guards/mod.rs     | 20 ---------------
 src/notifications/events.rs    |  7 ++++--
 src/notifications/websocket.rs |  1 +
 src/routes/users/add_friend.rs | 46 +++++++++++++++++++++++-----------
 src/routes/users/get_avatar.rs |  7 ++++++
 src/routes/users/mod.rs        |  4 +++
 10 files changed, 55 insertions(+), 41 deletions(-)
 create mode 100644 src/routes/users/get_avatar.rs

diff --git a/.gitignore b/.gitignore
index 22ef502..27e8598 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ Rocket.toml
 **/*.rs.bk
 .mongo
 .env
+avatar.png
diff --git a/Cargo.lock b/Cargo.lock
index 7ea9f63..5e1586f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -983,8 +983,9 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
 
 [[package]]
 name = "hive_pubsub"
-version = "0.4.2"
-source = "git+https://gitlab.insrt.uk/insert/hive#7ab66da23bc86b6fa6497aac928d29d4b885a878"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83760410241f6db418bb15e54b506a0887e7240286e29e5b0d2d88f5d1659b24"
 dependencies = [
  "futures",
  "many-to-many",
diff --git a/Cargo.toml b/Cargo.toml
index 06e7c93..1a48cf2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,10 +15,11 @@ async-tungstenite = { version = "0.10.0", features = ["async-std-runtime"] }
 rauth = { git = "https://gitlab.insrt.uk/insert/rauth" }
 async-std = { version = "1.8.0", features = ["tokio02"] }
 
-hive_pubsub = { git = "https://gitlab.insrt.uk/insert/hive", features = ["mongo"] }
+hive_pubsub = { version = "0.4.3", features = ["mongo"] }
 rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" }
 rocket_contrib = { git = "https://github.com/SergioBenitez/Rocket", branch = "master" }
 rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", default-features = false }
+# ! FIXME: Switch to async-std runtime.
 mongodb = { version = "1.1.1", features = ["tokio-runtime"], default-features = false }
 
 once_cell = "1.4.1"
diff --git a/Dockerfile b/Dockerfile
index 3377024..819d37b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 # Build Stage
-FROM ekidd/rust-musl-builder:nightly-2020-08-26 AS builder
+FROM ekidd/rust-musl-builder:nightly-2020-11-19 AS builder
 WORKDIR /home/rust/src
 
 RUN USER=root cargo new --bin revolt
diff --git a/src/database/guards/mod.rs b/src/database/guards/mod.rs
index 339d4c8..92488ee 100644
--- a/src/database/guards/mod.rs
+++ b/src/database/guards/mod.rs
@@ -1,22 +1,2 @@
 pub mod reference;
 pub mod user;
-
-/*
-// ! FIXME
-impl<'r> FromParam<'r> for User {
-    type Error = &'r RawStr;
-
-    fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
-        Err(param)
-        /*if let Ok(result) = fetch_channel(param).await {
-            if let Some(channel) = result {
-                Ok(channel)
-            } else {
-                Err(param)
-            }
-        } else {
-            Err(param)
-        }*/
-    }
-}
-*/
diff --git a/src/notifications/events.rs b/src/notifications/events.rs
index 9da5f81..0cda340 100644
--- a/src/notifications/events.rs
+++ b/src/notifications/events.rs
@@ -2,12 +2,12 @@ use rauth::auth::Session;
 use serde::{Deserialize, Serialize};
 use snafu::Snafu;
 
-use crate::database::entities::RelationshipStatus;
+use crate::database::entities::{RelationshipStatus, User};
 
 use super::hive::get_hive;
 
 #[derive(Serialize, Deserialize, Debug, Snafu)]
-#[serde(tag = "type")]
+#[serde(tag = "error")]
 pub enum WebSocketError {
     #[snafu(display("This error has not been labelled."))]
     LabelMe,
@@ -32,6 +32,9 @@ pub enum ServerboundNotification {
 pub enum ClientboundNotification {
     Error(WebSocketError),
     Authenticated,
+    Ready {
+        user: User
+    },
 
     /*MessageCreate {
         id: String,
diff --git a/src/notifications/websocket.rs b/src/notifications/websocket.rs
index 5e2bf69..dd47235 100644
--- a/src/notifications/websocket.rs
+++ b/src/notifications/websocket.rs
@@ -96,6 +96,7 @@ async fn accept(stream: TcpStream) {
                                                 subscriptions::generate_subscriptions(&user),
                                             ) {
                                                 send(ClientboundNotification::Authenticated);
+                                                send(ClientboundNotification::Ready { user });
                                             } else {
                                                 send(ClientboundNotification::Error(
                                                     WebSocketError::InternalError,
diff --git a/src/routes/users/add_friend.rs b/src/routes/users/add_friend.rs
index c031909..091728a 100644
--- a/src/routes/users/add_friend.rs
+++ b/src/routes/users/add_friend.rs
@@ -13,13 +13,29 @@ use crate::{
 };
 use futures::try_join;
 use mongodb::bson::doc;
+use mongodb::options::{FindOneOptions, Collation};
 use rocket_contrib::json::JsonValue;
 
-#[put("/<target>/friend")]
-pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+#[put("/<username>/friend")]
+pub async fn req(user: User, username: String) -> Result<JsonValue> {
     let col = get_collection("users");
+    let doc = col.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" })?
+    .ok_or_else(|| Error::UnknownUser)?;
 
-    match get_relationship(&user, &target) {
+    let target_id = doc
+        .get_str("_id")
+        .map_err(|_| Error::DatabaseError { operation: "get_str(_id)", with: "user" })?;
+
+    match get_relationship(&user, &Ref { id: target_id.to_string() }) {
         RelationshipStatus::User => return Err(Error::NoEffect),
         RelationshipStatus::Friend => return Err(Error::AlreadyFriends),
         RelationshipStatus::Outgoing => return Err(Error::AlreadySentRequest),
@@ -30,7 +46,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                 col.update_one(
                     doc! {
                         "_id": &user.id,
-                        "relations._id": &target.id
+                        "relations._id": target_id
                     },
                     doc! {
                         "$set": {
@@ -41,7 +57,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                 ),
                 col.update_one(
                     doc! {
-                        "_id": &target.id,
+                        "_id": target_id,
                         "relations._id": &user.id
                     },
                     doc! {
@@ -56,16 +72,16 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                     try_join!(
                         ClientboundNotification::UserRelationship {
                             id: user.id.clone(),
-                            user: target.id.clone(),
+                            user: target_id.to_string(),
                             status: RelationshipStatus::Friend
                         }
                         .publish(user.id.clone()),
                         ClientboundNotification::UserRelationship {
-                            id: target.id.clone(),
+                            id: target_id.to_string(),
                             user: user.id.clone(),
                             status: RelationshipStatus::Friend
                         }
-                        .publish(target.id.clone())
+                        .publish(target_id.to_string())
                     )
                     .ok();
 
@@ -86,7 +102,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                     doc! {
                         "$push": {
                             "relations": {
-                                "_id": &target.id,
+                                "_id": target_id,
                                 "status": "Outgoing"
                             }
                         }
@@ -95,7 +111,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                 ),
                 col.update_one(
                     doc! {
-                        "_id": &target.id
+                        "_id": target_id
                     },
                     doc! {
                         "$push": {
@@ -112,21 +128,21 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
                     try_join!(
                         ClientboundNotification::UserRelationship {
                             id: user.id.clone(),
-                            user: target.id.clone(),
+                            user: target_id.to_string(),
                             status: RelationshipStatus::Outgoing
                         }
                         .publish(user.id.clone()),
                         ClientboundNotification::UserRelationship {
-                            id: target.id.clone(),
+                            id: target_id.to_string(),
                             user: user.id.clone(),
                             status: RelationshipStatus::Incoming
                         }
-                        .publish(target.id.clone())
+                        .publish(target_id.to_string())
                     )
                     .ok();
 
-                    hive::subscribe_if_exists(user.id.clone(), target.id.clone()).ok();
-                    hive::subscribe_if_exists(target.id.clone(), user.id.clone()).ok();
+                    hive::subscribe_if_exists(user.id.clone(), target_id.to_string()).ok();
+                    hive::subscribe_if_exists(target_id.to_string(), user.id.clone()).ok();
 
                     Ok(json!({ "status": "Outgoing" }))
                 }
diff --git a/src/routes/users/get_avatar.rs b/src/routes/users/get_avatar.rs
new file mode 100644
index 0000000..64ee74e
--- /dev/null
+++ b/src/routes/users/get_avatar.rs
@@ -0,0 +1,7 @@
+use rocket::response::NamedFile;
+use std::path::Path;
+
+#[get("/<_target>/avatar")]
+pub async fn req(_target: String) -> Option<NamedFile> {
+    NamedFile::open(Path::new("avatar.png")).await.ok()
+}
diff --git a/src/routes/users/mod.rs b/src/routes/users/mod.rs
index 8f7b4ec..0f748d8 100644
--- a/src/routes/users/mod.rs
+++ b/src/routes/users/mod.rs
@@ -1,6 +1,7 @@
 use rocket::Route;
 
 mod add_friend;
+mod get_avatar;
 mod block_user;
 mod fetch_dms;
 mod fetch_relationship;
@@ -14,9 +15,12 @@ pub fn routes() -> Vec<Route> {
     routes![
         // User Information
         fetch_user::req,
+        get_avatar::req,
+
         // Direct Messaging
         fetch_dms::req,
         open_dm::req,
+
         // Relationships
         fetch_relationships::req,
         fetch_relationship::req,
-- 
GitLab