Repository: revoltchat/backend (language: rust)

Issue:
issue: restoring view permissions on channel on a role does not propagate to client
Reproduction:
1. Hide a channel from `@everyone`.
2. Allow view permissions for a single role.
3. Users with role do not immediately see the channel.


Discussion / hints:

Fix patch:
diff --git a/crates/quark/src/events/impl.rs b/crates/quark/src/events/impl.rs
index 1c7e3e4a4..d8bb85bf9 100644
--- a/crates/quark/src/events/impl.rs
+++ b/crates/quark/src/events/impl.rs
@@ -23,8 +23,7 @@ impl Cache {
     pub async fn can_view_channel(&self, db: &Database, channel: &Channel) -> bool {
         match &channel {
             Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
-                let member = self.members.values().find(|x| &x.id.server == server);
-
+                let member = self.members.get(server);
                 let server = self.servers.get(server);
                 let mut perms = perms(self.users.get(&self.user_id).unwrap()).channel(channel);
 
@@ -107,9 +106,15 @@ impl State {
 
         // Fetch all memberships with their corresponding servers.
         let members: Vec<Member> = db.fetch_all_memberships(&user.id).await?;
+        self.cache.members = members
+            .iter()
+            .cloned()
+            .map(|x| (x.id.server.clone(), x))
+            .collect();
 
         let server_ids: Vec<String> = members.iter().map(|x| x.id.server.clone()).collect();
         let servers = db.fetch_servers(&server_ids).await?;
+        self.cache.servers = servers.iter().cloned().map(|x| (x.id.clone(), x)).collect();
 
         // Collect channel ids from servers.
         let mut channel_ids = vec![];
@@ -164,17 +169,11 @@ impl State {
         self.cache
             .users
             .insert(self.cache.user_id.clone(), user.clone());
-        self.cache.servers = servers.iter().cloned().map(|x| (x.id.clone(), x)).collect();
         self.cache.channels = channels
             .iter()
             .cloned()
             .map(|x| (x.id().to_string(), x))
             .collect();
-        self.cache.members = members
-            .iter()
-            .cloned()
-            .map(|x| (x.id.server.clone(), x))
-            .collect();
 
         // Make all users appear from our perspective.
         let mut users: Vec<User> = users
@@ -353,7 +352,7 @@ impl State {
                 let could_view: bool = if let Some(channel) = self.cache.channels.get(id) {
                     self.cache.can_view_channel(db, channel).await
                 } else {
-                    true
+                    false
                 };
 
                 if let Some(channel) = self.cache.channels.get_mut(id) {
@@ -364,6 +363,12 @@ impl State {
                     channel.apply_options(data.clone());
                 }
 
+                if !self.cache.channels.contains_key(id) {
+                    if let Ok(channel) = db.fetch_channel(id).await {
+                        self.cache.channels.insert(id.clone(), channel);
+                    }
+                }
+
                 if let Some(channel) = self.cache.channels.get(id) {
                     let can_view = self.cache.can_view_channel(db, channel).await;
                     if could_view != can_view {
@@ -398,7 +403,9 @@ impl State {
                 channels,
             } => {
                 self.insert_subscription(id.clone());
-                self.cache.servers.insert(id.to_string(), server.clone());
+                self.cache.servers.insert(id.clone(), server.clone());
+                let member = Member::new(id.clone(), self.cache.user_id.clone());
+                self.cache.members.insert(id.clone(), member);
 
                 for channel in channels {
                     self.cache
@@ -436,6 +443,7 @@ impl State {
                             self.cache.channels.remove(channel);
                         }
                     }
+                    self.cache.members.remove(id);
                 }
             }
             EventV1::ServerDelete { id } => {
@@ -447,6 +455,7 @@ impl State {
                         self.cache.channels.remove(channel);
                     }
                 }
+                self.cache.members.remove(id);
             }
             EventV1::ServerMemberUpdate { id, data, clear } => {
                 if id.user == self.cache.user_id {
diff --git a/crates/quark/src/impl/dummy/servers/server_member.rs b/crates/quark/src/impl/dummy/servers/server_member.rs
index f0b9eff41..87aaf0332 100644
--- a/crates/quark/src/impl/dummy/servers/server_member.rs
+++ b/crates/quark/src/impl/dummy/servers/server_member.rs
@@ -3,22 +3,10 @@ use crate::{AbstractServerMember, Result};
 
 use super::super::DummyDb;
 
-use iso8601_timestamp::Timestamp;
-
 #[async_trait]
 impl AbstractServerMember for DummyDb {
     async fn fetch_member(&self, server: &str, user: &str) -> Result<Member> {
-        Ok(Member {
-            id: MemberCompositeKey {
-                server: server.into(),
-                user: user.into(),
-            },
-            joined_at: Timestamp::now_utc(),
-            nickname: None,
-            avatar: None,
-            roles: vec![],
-            timeout: None,
-        })
+        Ok(Member::new(server.into(), user.into()))
     }
 
     async fn insert_member(&self, member: &Member) -> Result<()> {
diff --git a/crates/quark/src/impl/generic/servers/server.rs b/crates/quark/src/impl/generic/servers/server.rs
index 20b88f06e..8131eecd2 100644
--- a/crates/quark/src/impl/generic/servers/server.rs
+++ b/crates/quark/src/impl/generic/servers/server.rs
@@ -1,6 +1,5 @@
 use std::collections::HashSet;
 
-use iso8601_timestamp::Timestamp;
 use ulid::Ulid;
 
 use crate::{
@@ -186,18 +185,7 @@ impl Server {
             return Err(Error::Banned);
         }
 
-        let member = Member {
-            id: MemberCompositeKey {
-                server: self.id.clone(),
-                user: user.id.clone(),
-            },
-            joined_at: Timestamp::now_utc(),
-            nickname: None,
-            avatar: None,
-            roles: vec![],
-            timeout: None,
-        };
-
+        let member = Member::new(self.id.clone(), user.id.clone());
         db.insert_member(&member).await?;
 
         let should_fetch = channels.is_none();
diff --git a/crates/quark/src/impl/generic/servers/server_member.rs b/crates/quark/src/impl/generic/servers/server_member.rs
index 8ec6ea83b..217fbd040 100644
--- a/crates/quark/src/impl/generic/servers/server_member.rs
+++ b/crates/quark/src/impl/generic/servers/server_member.rs
@@ -3,13 +3,27 @@ use iso8601_timestamp::Timestamp;
 use crate::{
     events::client::EventV1,
     models::{
-        server_member::{FieldsMember, PartialMember},
+        server_member::{FieldsMember, MemberCompositeKey, PartialMember},
         Member, Server,
     },
     Database, Result,
 };
 
 impl Member {
+    pub fn new(server_id: String, user_id: String) -> Self {
+        Self {
+            id: MemberCompositeKey {
+                server: server_id,
+                user: user_id,
+            },
+            joined_at: Timestamp::now_utc(),
+            nickname: None,
+            avatar: None,
+            roles: vec![],
+            timeout: None,
+        }
+    }
+
     /// Update member data
     pub async fn update<'a>(
         &mut self,


Test patch: