diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..b458b995e10b004df89e7e4b0af934d183d66266 --- /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 612f5003cd1b598b483658fbed9a5afc021dec0d..20bc4ec6f00cb262e9f73c79c4aed4d2d40bbe8a 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 0422bb740a5facded0e17dc48d6d713b6a08c908..ba3470967f097d4e02efcf2458a633e5fb4cd3bb 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 <paulmakles@gmail.com>"] edition = "2018" diff --git a/src/database/entities/user.rs b/src/database/entities/user.rs index e7c0e614b60de2afe1e3d587fdc0fffae3957119..165e9a163314ab718334285a853dbf42aa5085d5 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<User> { + 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<bool> { if username.to_lowercase() == "revolt" && username.to_lowercase() == "admin" { diff --git a/src/database/permissions/mod.rs b/src/database/permissions/mod.rs index 7fc9b26eb89eda009c677d5c83885cfac40df000..61644789d3f032a09b5c041b1375cce557d65dbe 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 7d516eef7d038f560a8f127e35f8d21c3064ed39..f4d7c581bbc02dc459e9d67acd8f94f128c2e711 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 4e92bdb9113f6fc8e196bdffdcecc94a94f5ddd3..a71f0ae77bd7dcaa96a557cfacf243e432e6c05c 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 1f2be02f919f61f41a0324162e072da38abab98c..669b08c27307b6e3f7729b04c094b798e22097e0 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 f918fc8e340038d9e5cdae3132ec03dc4c808ebc..8d5cbef761268f82505ae1892e7c9f007ebddd42 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<JsonValue> { 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<JsonValue> { ) ) { 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<JsonValue> { ) ) { 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 1fb51831da77965a9e0e7f254ba15d5e67dbf3c8..a554c289059363b6f7148c1ba1ef933166cb6ad4 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<JsonValue> { 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<JsonValue> { 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<JsonValue> { ) ) { 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<JsonValue> { ) ) { 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 37e831a174ff6ff57e47f0d62e9eedab04bd45d5..882594d870c37548331e6459d31bea97a9a4c313 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<JsonValue> { 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<JsonValue> { ) ) { 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 ec575c4bda7c404eca4597497186849a6de4a2ec..8be43035b1d914090691aff150ebc342313285bb 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("/<target>/block")] pub async fn req(user: User, target: Ref) -> Result<JsonValue> { 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<JsonValue> { 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<JsonValue> { ) ) { 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();