From af8731ac38bca16550a724027284093f3c24dd8f Mon Sep 17 00:00:00 2001
From: Paul Makles <paulmakles@gmail.com>
Date: Mon, 18 Jan 2021 13:41:48 +0000
Subject: [PATCH] Start development sprint 3.

---
 Cargo.lock                           |  2 +-
 Cargo.toml                           |  2 +-
 src/database/entities/channel.rs     | 36 ++--------------------------
 src/database/guards/reference.rs     | 24 ++++++++++++-------
 src/database/permissions/channel.rs  | 33 +++++++++++++++++++++++++
 src/database/permissions/mod.rs      |  1 +
 src/routes/channels/fetch_channel.rs | 16 +++++++++++++
 src/routes/channels/mod.rs           |  6 ++++-
 8 files changed, 75 insertions(+), 45 deletions(-)
 create mode 100644 src/database/permissions/channel.rs
 create mode 100644 src/routes/channels/fetch_channel.rs

diff --git a/Cargo.lock b/Cargo.lock
index b24b97f..335baed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2273,7 +2273,7 @@ dependencies = [
 
 [[package]]
 name = "revolt"
-version = "0.3.0-alpha"
+version = "0.3.1"
 dependencies = [
  "async-std",
  "async-tungstenite",
diff --git a/Cargo.toml b/Cargo.toml
index d5813bd..e8d14fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "revolt"
-version = "0.3.0-alpha"
+version = "0.3.1"
 authors = ["Paul Makles <paulmakles@gmail.com>"]
 edition = "2018"
 
diff --git a/src/database/entities/channel.rs b/src/database/entities/channel.rs
index ad10efc..42bc1fc 100644
--- a/src/database/entities/channel.rs
+++ b/src/database/entities/channel.rs
@@ -1,39 +1,7 @@
-use crate::{
-    database::get_collection,
-    util::result::{Error, Result},
-};
+use crate::database::*;
 use mongodb::bson::to_document;
 use serde::{Deserialize, Serialize};
-
-/*#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct LastMessage {
-    id: String,
-    user_id: String,
-    short_content: String,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct Channel {
-    #[serde(rename = "_id")]
-    pub id: String,
-    #[serde(rename = "type")]
-    pub channel_type: u8,
-
-    // DM: whether the DM is active
-    pub active: Option<bool>,
-    // DM + GDM: last message in channel
-    pub last_message: Option<LastMessage>,
-    // DM + GDM: recipients for channel
-    pub recipients: Option<Vec<String>>,
-    // GDM: owner of group
-    pub owner: Option<String>,
-    // GUILD: channel parent
-    pub guild: Option<String>,
-    // GUILD + GDM: channel name
-    pub name: Option<String>,
-    // GUILD + GDM: channel description
-    pub description: Option<String>,
-}*/
+use crate::util::result::{Error, Result};
 
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(tag = "type")]
diff --git a/src/database/guards/reference.rs b/src/database/guards/reference.rs
index bdad5ce..a71a90e 100644
--- a/src/database/guards/reference.rs
+++ b/src/database/guards/reference.rs
@@ -1,11 +1,11 @@
 use crate::database::*;
 use crate::util::result::{Error, Result};
 
-use mongodb::bson::{doc, from_bson, Bson};
+use validator::Validate;
 use rocket::http::RawStr;
 use rocket::request::FromParam;
-use serde::{Deserialize, Serialize};
-use validator::Validate;
+use mongodb::bson::{doc, from_bson, Bson};
+use serde::{Deserialize, Serialize, de::DeserializeOwned};
 
 #[derive(Validate, Serialize, Deserialize)]
 pub struct Ref {
@@ -18,8 +18,8 @@ impl Ref {
         Ok(Ref { id })
     }
 
-    pub async fn fetch_user(&self) -> Result<User> {
-        let doc = get_collection("users")
+    pub async fn fetch<T: DeserializeOwned>(&self, collection: &'static str) -> Result<T> {
+        let doc = get_collection(&collection)
             .find_one(
                 doc! {
                     "_id": &self.id
@@ -29,17 +29,25 @@ impl Ref {
             .await
             .map_err(|_| Error::DatabaseError {
                 operation: "find_one",
-                with: "user",
+                with: &collection,
             })?
             .ok_or_else(|| Error::UnknownUser)?;
 
         Ok(
-            from_bson(Bson::Document(doc)).map_err(|_| Error::DatabaseError {
+            from_bson::<T>(Bson::Document(doc)).map_err(|_| Error::DatabaseError {
                 operation: "from_bson",
-                with: "user",
+                with: &collection,
             })?,
         )
     }
+
+    pub async fn fetch_user(&self) -> Result<User> {
+        self.fetch("users").await
+    }
+
+    pub async fn fetch_channel(&self) -> Result<Channel> {
+        self.fetch("channels").await
+    }
 }
 
 impl User {
diff --git a/src/database/permissions/channel.rs b/src/database/permissions/channel.rs
new file mode 100644
index 0000000..cfb4ebd
--- /dev/null
+++ b/src/database/permissions/channel.rs
@@ -0,0 +1,33 @@
+use crate::database::*;
+use num_enum::TryFromPrimitive;
+use std::ops;
+
+#[derive(Debug, PartialEq, Eq, TryFromPrimitive, Copy, Clone)]
+#[repr(u32)]
+pub enum ChannelPermission {
+    View = 1,
+    SendMessage = 2,
+}
+
+bitfield! {
+    pub struct ChannelPermissions(MSB0 [u32]);
+    u32;
+    pub get_view, _: 31;
+    pub get_send_message, _: 30;
+}
+
+impl_op_ex!(+ |a: &ChannelPermission, b: &ChannelPermission| -> u32 { *a as u32 | *b as u32 });
+impl_op_ex_commutative!(+ |a: &u32, b: &ChannelPermission| -> u32 { *a | *b as u32 });
+
+pub async fn calculate(user: &User, target: &Channel) -> ChannelPermissions<[u32; 1]> {
+    match target {
+        Channel::SavedMessages { user: owner, .. } => {
+            if &user.id == owner {
+                ChannelPermissions([ ChannelPermission::View + ChannelPermission::SendMessage ])
+            } else {
+                ChannelPermissions([ 0 ])
+            }
+        }
+        _ => unreachable!()
+    }
+}
diff --git a/src/database/permissions/mod.rs b/src/database/permissions/mod.rs
index 4565ef9..0240b8b 100644
--- a/src/database/permissions/mod.rs
+++ b/src/database/permissions/mod.rs
@@ -1,3 +1,4 @@
 pub mod user;
+pub mod channel;
 
 pub use user::get_relationship;
diff --git a/src/routes/channels/fetch_channel.rs b/src/routes/channels/fetch_channel.rs
new file mode 100644
index 0000000..4d95960
--- /dev/null
+++ b/src/routes/channels/fetch_channel.rs
@@ -0,0 +1,16 @@
+use crate::database::*;
+use crate::util::result::{Error, Result};
+
+use rocket_contrib::json::JsonValue;
+
+#[get("/<target>")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let target = target.fetch_channel().await?;
+
+    let perm = permissions::channel::calculate(&user, &target).await;
+    if !perm.get_view() {
+        Err(Error::LabelMe)?
+    }
+
+    Ok(json!(target))
+}
diff --git a/src/routes/channels/mod.rs b/src/routes/channels/mod.rs
index 018a956..2137b3c 100644
--- a/src/routes/channels/mod.rs
+++ b/src/routes/channels/mod.rs
@@ -1,5 +1,9 @@
 use rocket::Route;
 
+mod fetch_channel;
+
 pub fn routes() -> Vec<Route> {
-    routes![]
+    routes![
+        fetch_channel::req
+    ]
 }
-- 
GitLab