diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b458b995 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.diagnostics.disabled": [ + "unresolved-macro-call" + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 612f5003..20bc4ec6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2475,7 +2475,7 @@ dependencies = [ [[package]] name = "revolt" -version = "0.4.1-alpha.1" +version = "0.4.1-alpha.2" dependencies = [ "async-std", "async-tungstenite", diff --git a/Cargo.toml b/Cargo.toml index 0422bb74..ba347096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt" -version = "0.4.1-alpha.1" +version = "0.4.1-alpha.2" authors = ["Paul Makles "] edition = "2018" diff --git a/src/database/entities/user.rs b/src/database/entities/user.rs index e7c0e614..165e9a16 100644 --- a/src/database/entities/user.rs +++ b/src/database/entities/user.rs @@ -82,6 +82,8 @@ pub struct User { impl User { /// Mutate the user object to include relationship as seen by user. pub fn from(mut self, user: &User) -> User { + self.relationship = Some(RelationshipStatus::None); + if self.id == user.id { self.relationship = Some(RelationshipStatus::User); return self; @@ -102,12 +104,26 @@ impl User { pub fn with(mut self, permissions: UserPermissions<[u32; 1]>) -> User { if permissions.get_view_profile() { self.online = Some(is_online(&self.id)); + } else { + self.status = None; } self.profile = None; self } + /// Mutate the user object to appear as seen by user. + /// Also overrides the relationship status. + pub async fn from_override(mut self, user: &User, relationship: RelationshipStatus) -> Result { + let permissions = PermissionCalculator::new(&user) + .with_relationship(&relationship) + .for_user(&self.id).await?; + + self.relations = None; + self.relationship = Some(relationship); + Ok(self.with(permissions)) + } + /// Utility function for checking claimed usernames. pub async fn is_username_taken(username: &str) -> Result { if username.to_lowercase() == "revolt" && username.to_lowercase() == "admin" { diff --git a/src/database/permissions/mod.rs b/src/database/permissions/mod.rs index 7fc9b26e..61644789 100644 --- a/src/database/permissions/mod.rs +++ b/src/database/permissions/mod.rs @@ -9,6 +9,7 @@ pub struct PermissionCalculator<'a> { perspective: &'a User, user: Option<&'a User>, + relationship: Option<&'a RelationshipStatus>, channel: Option<&'a Channel>, has_mutual_connection: bool, @@ -20,6 +21,7 @@ impl<'a> PermissionCalculator<'a> { perspective, user: None, + relationship: None, channel: None, has_mutual_connection: false, @@ -33,6 +35,13 @@ impl<'a> PermissionCalculator<'a> { } } + pub fn with_relationship(self, relationship: &'a RelationshipStatus) -> PermissionCalculator { + PermissionCalculator { + relationship: Some(&relationship), + ..self + } + } + pub fn with_channel(self, channel: &'a Channel) -> PermissionCalculator { PermissionCalculator { channel: Some(&channel), diff --git a/src/database/permissions/user.rs b/src/database/permissions/user.rs index 7d516eef..f4d7c581 100644 --- a/src/database/permissions/user.rs +++ b/src/database/permissions/user.rs @@ -49,7 +49,7 @@ impl<'a> PermissionCalculator<'a> { } let mut permissions: u32 = 0; - match get_relationship(&self.perspective, &target) { + match self.relationship.clone().map(|v| v.to_owned()).unwrap_or_else(|| get_relationship(&self.perspective, &target)) { RelationshipStatus::Friend => return Ok(u32::MAX), RelationshipStatus::Blocked | RelationshipStatus::BlockedOther => { return Ok(UserPermission::Access as u32) diff --git a/src/notifications/events.rs b/src/notifications/events.rs index 4e92bdb9..a71f0ae7 100644 --- a/src/notifications/events.rs +++ b/src/notifications/events.rs @@ -80,8 +80,8 @@ pub enum ClientboundNotification { }, UserRelationship { id: String, - user: String, - status: RelationshipStatus, + user: User, + status: RelationshipStatus }, UserPresence { id: String, @@ -116,7 +116,7 @@ pub fn prehandle_hook(notification: &ClientboundNotification) { } ClientboundNotification::UserRelationship { id, user, status } => { if status != &RelationshipStatus::None { - subscribe_if_exists(id.clone(), user.clone()).ok(); + subscribe_if_exists(id.clone(), user.id.clone()).ok(); } } _ => {} @@ -132,7 +132,7 @@ pub fn posthandle_hook(notification: &ClientboundNotification) { if status == &RelationshipStatus::None { get_hive() .hive - .unsubscribe(&id.to_string(), &user.to_string()) + .unsubscribe(&id.to_string(), &user.id.to_string()) .ok(); } } diff --git a/src/routes/root.rs b/src/routes/root.rs index 1f2be02f..669b08c2 100644 --- a/src/routes/root.rs +++ b/src/routes/root.rs @@ -9,7 +9,7 @@ use rocket_contrib::json::JsonValue; #[get("/")] pub async fn root() -> JsonValue { json!({ - "revolt": "0.4.1-alpha.1", + "revolt": "0.4.1-alpha.2", "features": { "registration": !*DISABLE_REGISTRATION, "captcha": { diff --git a/src/routes/users/add_friend.rs b/src/routes/users/add_friend.rs index f918fc8e..8d5cbef7 100644 --- a/src/routes/users/add_friend.rs +++ b/src/routes/users/add_friend.rs @@ -31,6 +31,8 @@ pub async fn req(user: User, username: String) -> Result { with: "user", })?; + let target_user = Ref::from(target_id.to_string())?.fetch_user().await?; + match get_relationship(&user, &target_id) { RelationshipStatus::User => return Err(Error::NoEffect), RelationshipStatus::Friend => return Err(Error::AlreadyFriends), @@ -65,16 +67,19 @@ pub async fn req(user: User, username: String) -> Result { ) ) { Ok(_) => { + let target_user = target_user.from_override(&user, RelationshipStatus::Friend).await?; + let user = user.from_override(&target_user, RelationshipStatus::Friend).await?; + try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target_id.to_string(), + user: target_user, status: RelationshipStatus::Friend } .publish(user.id.clone()), ClientboundNotification::UserRelationship { id: target_id.to_string(), - user: user.id.clone(), + user, status: RelationshipStatus::Friend } .publish(target_id.to_string()) @@ -121,16 +126,18 @@ pub async fn req(user: User, username: String) -> Result { ) ) { Ok(_) => { + let target_user = target_user.from_override(&user, RelationshipStatus::Outgoing).await?; + let user = user.from_override(&target_user, RelationshipStatus::Incoming).await?; try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target_id.to_string(), + user: target_user, status: RelationshipStatus::Outgoing } .publish(user.id.clone()), ClientboundNotification::UserRelationship { id: target_id.to_string(), - user: user.id.clone(), + user, status: RelationshipStatus::Incoming } .publish(target_id.to_string()) diff --git a/src/routes/users/block_user.rs b/src/routes/users/block_user.rs index 1fb51831..a554c289 100644 --- a/src/routes/users/block_user.rs +++ b/src/routes/users/block_user.rs @@ -10,6 +10,8 @@ use rocket_contrib::json::JsonValue; pub async fn req(user: User, target: Ref) -> Result { let col = get_collection("users"); + let target = target.fetch_user().await?; + match get_relationship(&user, &target.id) { RelationshipStatus::User | RelationshipStatus::Blocked => Err(Error::NoEffect), RelationshipStatus::BlockedOther => { @@ -33,7 +35,7 @@ pub async fn req(user: User, target: Ref) -> Result { ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::Blocked, } .publish(user.id.clone()) @@ -74,19 +76,23 @@ pub async fn req(user: User, target: Ref) -> Result { ) ) { Ok(_) => { + let target = target.from_override(&user, RelationshipStatus::Friend).await?; + let user = user.from_override(&target, RelationshipStatus::Friend).await?; + let target_id = target.id.clone(); + try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::Blocked } .publish(user.id.clone()), ClientboundNotification::UserRelationship { - id: target.id.clone(), - user: user.id.clone(), + id: target_id.clone(), + user, status: RelationshipStatus::BlockedOther } - .publish(target.id.clone()) + .publish(target_id) ) .ok(); @@ -128,19 +134,23 @@ pub async fn req(user: User, target: Ref) -> Result { ) ) { Ok(_) => { + let target = target.from_override(&user, RelationshipStatus::Blocked).await?; + let user = user.from_override(&target, RelationshipStatus::BlockedOther).await?; + let target_id = target.id.clone(); + try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::Blocked } .publish(user.id.clone()), ClientboundNotification::UserRelationship { - id: target.id.clone(), - user: user.id.clone(), + id: target_id.clone(), + user, status: RelationshipStatus::BlockedOther } - .publish(target.id.clone()) + .publish(target_id) ) .ok(); diff --git a/src/routes/users/remove_friend.rs b/src/routes/users/remove_friend.rs index 37e831a1..882594d8 100644 --- a/src/routes/users/remove_friend.rs +++ b/src/routes/users/remove_friend.rs @@ -10,6 +10,8 @@ use rocket_contrib::json::JsonValue; pub async fn req(user: User, target: Ref) -> Result { let col = get_collection("users"); + let target = target.fetch_user().await?; + match get_relationship(&user, &target.id) { RelationshipStatus::Friend | RelationshipStatus::Outgoing @@ -43,19 +45,23 @@ pub async fn req(user: User, target: Ref) -> Result { ) ) { Ok(_) => { + let target = target.from_override(&user, RelationshipStatus::None).await?; + let user = user.from_override(&target, RelationshipStatus::None).await?; + let target_id = target.id.clone(); + try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::None } .publish(user.id.clone()), ClientboundNotification::UserRelationship { - id: target.id.clone(), - user: user.id.clone(), + id: target_id.clone(), + user, status: RelationshipStatus::None } - .publish(target.id.clone()) + .publish(target_id) ) .ok(); diff --git a/src/routes/users/unblock_user.rs b/src/routes/users/unblock_user.rs index ec575c4b..8be43035 100644 --- a/src/routes/users/unblock_user.rs +++ b/src/routes/users/unblock_user.rs @@ -9,10 +9,11 @@ use rocket_contrib::json::JsonValue; #[delete("//block")] pub async fn req(user: User, target: Ref) -> Result { let col = get_collection("users"); + let target = target.fetch_user().await?; match get_relationship(&user, &target.id) { RelationshipStatus::Blocked => { - match get_relationship(&target.fetch_user().await?, &user.id) { + match get_relationship(&target, &user.id) { RelationshipStatus::Blocked => { col.update_one( doc! { @@ -32,9 +33,10 @@ pub async fn req(user: User, target: Ref) -> Result { with: "user", })?; + let target = target.from_override(&user, RelationshipStatus::BlockedOther).await?; ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::BlockedOther, } .publish(user.id.clone()) @@ -73,19 +75,23 @@ pub async fn req(user: User, target: Ref) -> Result { ) ) { Ok(_) => { + let target = target.from_override(&user, RelationshipStatus::None).await?; + let user = user.from_override(&target, RelationshipStatus::None).await?; + let target_id = target.id.clone(); + try_join!( ClientboundNotification::UserRelationship { id: user.id.clone(), - user: target.id.clone(), + user: target, status: RelationshipStatus::None } .publish(user.id.clone()), ClientboundNotification::UserRelationship { - id: target.id.clone(), - user: user.id.clone(), + id: target_id.clone(), + user: user, status: RelationshipStatus::None } - .publish(target.id.clone()) + .publish(target_id) ) .ok();