From 8a4a386ec577f3b33417bee99f3a703fe94ea0a7 Mon Sep 17 00:00:00 2001
From: Paul Makles <paulmakles@gmail.com>
Date: Thu, 9 Apr 2020 18:33:08 +0100
Subject: [PATCH] Add util, fix fetch DMs, fully implement delete.

---
 src/database/permissions.rs |  6 +--
 src/guards/channel.rs       |  1 +
 src/main.rs                 |  1 +
 src/routes/channel.rs       | 86 ++++++++++++++++++++++++++++++++-----
 src/routes/user.rs          | 38 ++++++++++++----
 src/util/mod.rs             |  6 +++
 6 files changed, 115 insertions(+), 23 deletions(-)
 create mode 100644 src/util/mod.rs

diff --git a/src/database/permissions.rs b/src/database/permissions.rs
index d5eaa73..0c20185 100644
--- a/src/database/permissions.rs
+++ b/src/database/permissions.rs
@@ -159,7 +159,7 @@ impl PermissionCalculator {
                         let mut other_user = "";
                         for item in arr {
                             if item == &self.user.id {
-                                permissions = 49;
+                                permissions = 177;
                             } else {
                                 other_user = item;
                             }
@@ -174,7 +174,7 @@ impl PermissionCalculator {
                         {
                             permissions = 1;
                         } else if has_mutual_connection(self.user.id, other_user.to_string()) {
-                            permissions = 49;
+                            permissions = 177;
                         }
                     }
                 }
@@ -188,7 +188,7 @@ impl PermissionCalculator {
                     if let Some(arr) = &channel.recipients {
                         for item in arr {
                             if item == &self.user.id {
-                                permissions = 49;
+                                permissions = 177;
                                 break;
                             }
                         }
diff --git a/src/guards/channel.rs b/src/guards/channel.rs
index 39323b0..756f8f3 100644
--- a/src/guards/channel.rs
+++ b/src/guards/channel.rs
@@ -64,6 +64,7 @@ impl<'r> FromParam<'r> for ChannelRef {
                         "type": 1,
                         "recipients": 1,
                         "guild": 1,
+                        "owner": 1,
                     })
                     .build(),
             )
diff --git a/src/main.rs b/src/main.rs
index a3de253..876bb51 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,6 +10,7 @@ pub mod database;
 pub mod email;
 pub mod guards;
 pub mod routes;
+pub mod util;
 pub mod websocket;
 
 use dotenv;
diff --git a/src/routes/channel.rs b/src/routes/channel.rs
index cd3f5b8..a9fedb6 100644
--- a/src/routes/channel.rs
+++ b/src/routes/channel.rs
@@ -5,6 +5,7 @@ use crate::database::{
 };
 use crate::guards::auth::UserRef;
 use crate::guards::channel::ChannelRef;
+use crate::util::vec_to_set;
 
 use bson::{doc, from_bson, Bson, Bson::UtcDatetime};
 use chrono::prelude::*;
@@ -51,11 +52,8 @@ pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
     let name: String = info.name.chars().take(32).collect();
     let nonce: String = info.nonce.chars().take(32).collect();
 
-    let mut set = HashSet::new();
+    let mut set = vec_to_set(&info.users);
     set.insert(user.id.clone());
-    for item in &info.users {
-        set.insert(item.clone());
-    }
 
     if set.len() > MAXGROUPSIZE {
         return Response::BadRequest(json!({ "error": "Maximum group size is 50." }));
@@ -109,11 +107,29 @@ pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
     with_permissions!(user, target);
 
     match target.channel_type {
-        0..=1 => Some(Response::Success(json!({
+        0 => Some(Response::Success(json!({
             "id": target.id,
             "type": target.channel_type,
             "recipients": target.recipients,
         }))),
+        1 => {
+            if let Some(info) = target.fetch_data(doc! {
+                "name": 1,
+                "description": 1,
+                "owner": 1,
+            }) {
+                Some(Response::Success(json!({
+                    "id": target.id,
+                    "type": target.channel_type,
+                    "recipients": target.recipients,
+                    "name": info.get_str("name").unwrap(),
+                    "owner": info.get_str("owner").unwrap(),
+                    "description": info.get_str("description").unwrap_or(""),
+                })))
+            } else {
+                None
+            }
+        },
         2 => {
             if let Some(info) = target.fetch_data(doc! {
                 "name": 1,
@@ -146,11 +162,33 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
     }
 
     let col = database::get_collection("channels");
+    let target_id = target.id.clone();
+
+    let try_delete = || {
+        let messages = database::get_collection("messages");
+
+        if messages.delete_many(
+            doc! { "channel": &target_id },
+            None
+        ).is_ok() {
+            if col.delete_one(
+                doc! { "_id": &target_id },
+                None
+            ).is_ok() {
+                Some(Response::Result(super::Status::Ok))
+            } else {
+                Some(Response::InternalServerError(json!({ "error": "Failed to delete group." })))
+            }
+        } else {
+            Some(Response::InternalServerError(json!({ "error": "Failed to delete messages." })))
+        }
+    };
+
     match target.channel_type {
         0 => {
             if col
                 .update_one(
-                    doc! { "_id": target.id },
+                    doc! { "_id": &target_id },
                     doc! { "$set": { "active": false } },
                     None,
                 )
@@ -164,14 +202,40 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
             }
         }
         1 => {
-            // ? TODO: group dm
+            let mut recipients =
+                vec_to_set(&target.recipients.expect("Missing recipients on Group DM."));
+            let owner = target.owner.expect("Missing owner on Group DM.");
 
-            Some(Response::Result(super::Status::Ok))
+            if recipients.len() == 1 {
+                try_delete()
+            } else {
+                recipients.remove(&user.id);
+                let new_owner = if owner == user.id {
+                    recipients.iter().next().unwrap()
+                } else {
+                    &owner
+                };
+
+                if col.update_one(
+                    doc! { "_id": target_id },
+                    doc! {
+                        "$set": {
+                            "owner": new_owner,
+                        },
+                        "$pull": {
+                            "recipients": &user.id,
+                        }
+                    },
+                    None
+                ).is_ok() {
+                    Some(Response::Result(super::Status::Ok))
+                } else {
+                    Some(Response::InternalServerError(json!({ "error": "Failed to remove you from the group." })))
+                }
+            }
         }
         2 => {
-            // ? TODO: guild
-
-            Some(Response::Result(super::Status::Ok))
+            try_delete()
         }
         _ => Some(Response::InternalServerError(
             json!({ "error": "Unknown error has occurred." }),
diff --git a/src/routes/user.rs b/src/routes/user.rs
index 7833d42..0126424 100644
--- a/src/routes/user.rs
+++ b/src/routes/user.rs
@@ -92,21 +92,41 @@ pub fn dms(user: UserRef) -> Response {
                 ],
                 "recipients": user.id
             },
-            None,
+            FindOptions::builder()
+                .projection(doc! {
+
+                })
+                .build(),
         )
         .expect("Failed channel lookup");
 
     let mut channels = Vec::new();
     for item in results {
-        let channel: Channel =
-            from_bson(bson::Bson::Document(item.unwrap())).expect("Failed to unwrap channel.");
+        if let Ok(doc) = item {
+            let id = doc.get_str("_id").unwrap();
+            let recipients = doc.get_array("recipients").unwrap();
 
-        channels.push(json!({
-            "id": channel.id,
-            "type": channel.channel_type,
-            "recipients": channel.recipients,
-            "active": channel.active.unwrap()
-        }));
+            match doc.get_i32("type").unwrap() {
+                0 => {
+                    channels.push(json!({
+                        "id": id,
+                        "type": 0,
+                        "recipients": recipients,
+                    }));
+                },
+                1 => {
+                    channels.push(json!({
+                        "id": id,
+                        "type": 1,
+                        "recipients": recipients,
+                        "name": doc.get_str("name").unwrap(),
+                        "owner": doc.get_str("owner").unwrap(),
+                        "description": doc.get_str("description").unwrap_or(""),
+                    }));
+                },
+                _ => unreachable!()
+            }
+        }
     }
 
     Response::Success(json!(channels))
diff --git a/src/util/mod.rs b/src/util/mod.rs
new file mode 100644
index 0000000..fe40409
--- /dev/null
+++ b/src/util/mod.rs
@@ -0,0 +1,6 @@
+use hashbrown::HashSet;
+use std::iter::FromIterator;
+
+pub fn vec_to_set<T: Clone + Eq + std::hash::Hash>(data: &Vec<T>) -> HashSet<T> {
+    HashSet::from_iter(data.iter().cloned())
+}
-- 
GitLab