Remove current user from contacts
Co-Authored-By: Nathan Sobo <nathan@zed.dev> Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
4b73239972
commit
1d1bd3975a
4 changed files with 264 additions and 336 deletions
|
@ -842,10 +842,7 @@ impl Db for PostgresDb {
|
||||||
.bind(user_id)
|
.bind(user_id)
|
||||||
.fetch(&self.pool);
|
.fetch(&self.pool);
|
||||||
|
|
||||||
let mut contacts = vec![Contact::Accepted {
|
let mut contacts = Vec::new();
|
||||||
user_id,
|
|
||||||
should_notify: false,
|
|
||||||
}];
|
|
||||||
while let Some(row) = rows.next().await {
|
while let Some(row) = rows.next().await {
|
||||||
let (user_id_a, user_id_b, a_to_b, accepted, should_notify) = row?;
|
let (user_id_a, user_id_b, a_to_b, accepted, should_notify) = row?;
|
||||||
|
|
||||||
|
@ -2026,13 +2023,7 @@ pub mod tests {
|
||||||
let user_3 = db.create_user("user3", None, false).await.unwrap();
|
let user_3 = db.create_user("user3", None, false).await.unwrap();
|
||||||
|
|
||||||
// User starts with no contacts
|
// User starts with no contacts
|
||||||
assert_eq!(
|
assert_eq!(db.get_contacts(user_1).await.unwrap(), vec![]);
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
|
||||||
vec![Contact::Accepted {
|
|
||||||
user_id: user_1,
|
|
||||||
should_notify: false
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
|
|
||||||
// User requests a contact. Both users see the pending request.
|
// User requests a contact. Both users see the pending request.
|
||||||
db.send_contact_request(user_1, user_2).await.unwrap();
|
db.send_contact_request(user_1, user_2).await.unwrap();
|
||||||
|
@ -2040,26 +2031,14 @@ pub mod tests {
|
||||||
assert!(!db.has_contact(user_2, user_1).await.unwrap());
|
assert!(!db.has_contact(user_2, user_1).await.unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
db.get_contacts(user_1).await.unwrap(),
|
||||||
&[
|
&[Contact::Outgoing { user_id: user_2 }],
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_1,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
Contact::Outgoing { user_id: user_2 }
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_2).await.unwrap(),
|
db.get_contacts(user_2).await.unwrap(),
|
||||||
&[
|
&[Contact::Incoming {
|
||||||
Contact::Incoming {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: true
|
||||||
should_notify: true
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// User 2 dismisses the contact request notification without accepting or rejecting.
|
// User 2 dismisses the contact request notification without accepting or rejecting.
|
||||||
|
@ -2072,16 +2051,10 @@ pub mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_2).await.unwrap(),
|
db.get_contacts(user_2).await.unwrap(),
|
||||||
&[
|
&[Contact::Incoming {
|
||||||
Contact::Incoming {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: false
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// User can't accept their own contact request
|
// User can't accept their own contact request
|
||||||
|
@ -2095,31 +2068,19 @@ pub mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
db.get_contacts(user_1).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_2,
|
||||||
user_id: user_1,
|
should_notify: true
|
||||||
should_notify: false
|
}],
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
assert!(db.has_contact(user_1, user_2).await.unwrap());
|
assert!(db.has_contact(user_1, user_2).await.unwrap());
|
||||||
assert!(db.has_contact(user_2, user_1).await.unwrap());
|
assert!(db.has_contact(user_2, user_1).await.unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_2).await.unwrap(),
|
db.get_contacts(user_2).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: false,
|
||||||
should_notify: false,
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Users cannot re-request existing contacts.
|
// Users cannot re-request existing contacts.
|
||||||
|
@ -2132,16 +2093,10 @@ pub mod tests {
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
db.get_contacts(user_1).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_2,
|
||||||
user_id: user_1,
|
should_notify: true,
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Users can dismiss notifications of other users accepting their requests.
|
// Users can dismiss notifications of other users accepting their requests.
|
||||||
|
@ -2150,16 +2105,10 @@ pub mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
db.get_contacts(user_1).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_2,
|
||||||
user_id: user_1,
|
should_notify: false,
|
||||||
should_notify: false
|
},]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Users send each other concurrent contact requests and
|
// Users send each other concurrent contact requests and
|
||||||
|
@ -2169,10 +2118,6 @@ pub mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_1).await.unwrap(),
|
db.get_contacts(user_1).await.unwrap(),
|
||||||
&[
|
&[
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_1,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
Contact::Accepted {
|
Contact::Accepted {
|
||||||
user_id: user_2,
|
user_id: user_2,
|
||||||
should_notify: false,
|
should_notify: false,
|
||||||
|
@ -2185,16 +2130,10 @@ pub mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_3).await.unwrap(),
|
db.get_contacts(user_3).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: false
|
||||||
should_notify: false
|
}],
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_3,
|
|
||||||
should_notify: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// User declines a contact request. Both users see that it is gone.
|
// User declines a contact request. Both users see that it is gone.
|
||||||
|
@ -2206,29 +2145,17 @@ pub mod tests {
|
||||||
assert!(!db.has_contact(user_3, user_2).await.unwrap());
|
assert!(!db.has_contact(user_3, user_2).await.unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_2).await.unwrap(),
|
db.get_contacts(user_2).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: false
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_2,
|
|
||||||
should_notify: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user_3).await.unwrap(),
|
db.get_contacts(user_3).await.unwrap(),
|
||||||
&[
|
&[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user_1,
|
||||||
user_id: user_1,
|
should_notify: false
|
||||||
should_notify: false
|
}],
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user_3,
|
|
||||||
should_notify: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2261,29 +2188,17 @@ pub mod tests {
|
||||||
assert_eq!(invite_count, 1);
|
assert_eq!(invite_count, 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user1).await.unwrap(),
|
db.get_contacts(user1).await.unwrap(),
|
||||||
[
|
[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user2,
|
||||||
user_id: user1,
|
should_notify: true
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user2,
|
|
||||||
should_notify: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user2).await.unwrap(),
|
db.get_contacts(user2).await.unwrap(),
|
||||||
[
|
[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user1,
|
||||||
user_id: user1,
|
should_notify: false
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user2,
|
|
||||||
should_notify: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// User 3 redeems the invite code and becomes a contact of user 1.
|
// User 3 redeems the invite code and becomes a contact of user 1.
|
||||||
|
@ -2296,10 +2211,6 @@ pub mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user1).await.unwrap(),
|
db.get_contacts(user1).await.unwrap(),
|
||||||
[
|
[
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user1,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
Contact::Accepted {
|
Contact::Accepted {
|
||||||
user_id: user2,
|
user_id: user2,
|
||||||
should_notify: true
|
should_notify: true
|
||||||
|
@ -2312,16 +2223,10 @@ pub mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user3).await.unwrap(),
|
db.get_contacts(user3).await.unwrap(),
|
||||||
[
|
[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user1,
|
||||||
user_id: user1,
|
should_notify: false
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user3,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Trying to reedem the code for the third time results in an error.
|
// Trying to reedem the code for the third time results in an error.
|
||||||
|
@ -2346,10 +2251,6 @@ pub mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user1).await.unwrap(),
|
db.get_contacts(user1).await.unwrap(),
|
||||||
[
|
[
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user1,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
Contact::Accepted {
|
Contact::Accepted {
|
||||||
user_id: user2,
|
user_id: user2,
|
||||||
should_notify: true
|
should_notify: true
|
||||||
|
@ -2366,16 +2267,10 @@ pub mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user4).await.unwrap(),
|
db.get_contacts(user4).await.unwrap(),
|
||||||
[
|
[Contact::Accepted {
|
||||||
Contact::Accepted {
|
user_id: user1,
|
||||||
user_id: user1,
|
should_notify: false
|
||||||
should_notify: false
|
}]
|
||||||
},
|
|
||||||
Contact::Accepted {
|
|
||||||
user_id: user4,
|
|
||||||
should_notify: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// An existing user cannot redeem invite codes.
|
// An existing user cannot redeem invite codes.
|
||||||
|
@ -2704,10 +2599,7 @@ pub mod tests {
|
||||||
|
|
||||||
async fn get_contacts(&self, id: UserId) -> Result<Vec<Contact>> {
|
async fn get_contacts(&self, id: UserId) -> Result<Vec<Contact>> {
|
||||||
self.background.simulate_random_delay().await;
|
self.background.simulate_random_delay().await;
|
||||||
let mut contacts = vec![Contact::Accepted {
|
let mut contacts = Vec::new();
|
||||||
user_id: id,
|
|
||||||
should_notify: false,
|
|
||||||
}];
|
|
||||||
|
|
||||||
for contact in self.contacts.lock().iter() {
|
for contact in self.contacts.lock().iter() {
|
||||||
if contact.requester_id == id {
|
if contact.requester_id == id {
|
||||||
|
|
|
@ -3909,78 +3909,122 @@ async fn test_contacts(
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![]),
|
]
|
||||||
("user_b", true, vec![]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
("user_a".to_string(), true, vec![]),
|
||||||
)
|
("user_c".to_string(), true, vec![])
|
||||||
});
|
]
|
||||||
}
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
("user_a".to_string(), true, vec![]),
|
||||||
|
("user_b".to_string(), true, vec![])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
// Share a project as client A.
|
// Share a project as client A.
|
||||||
client_a.fs.create_dir(Path::new("/a")).await.unwrap();
|
client_a.fs.create_dir(Path::new("/a")).await.unwrap();
|
||||||
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![("a", vec![])]),
|
]
|
||||||
("user_b", true, vec![]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
("user_a".to_string(), true, vec![("a".to_string(), vec![])]),
|
||||||
)
|
("user_c".to_string(), true, vec![])
|
||||||
});
|
]
|
||||||
}
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
("user_a".to_string(), true, vec![("a".to_string(), vec![])]),
|
||||||
|
("user_b".to_string(), true, vec![])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
let _project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await;
|
let _project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await;
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![("a", vec!["user_b"])]),
|
]
|
||||||
("user_b", true, vec![]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
(
|
||||||
)
|
"user_a".to_string(),
|
||||||
});
|
true,
|
||||||
}
|
vec![("a".to_string(), vec!["user_b".to_string()])]
|
||||||
|
),
|
||||||
|
("user_c".to_string(), true, vec![])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"user_a".to_string(),
|
||||||
|
true,
|
||||||
|
vec![("a".to_string(), vec!["user_b".to_string()])]
|
||||||
|
),
|
||||||
|
("user_b".to_string(), true, vec![])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
// Add a local project as client B
|
// Add a local project as client B
|
||||||
client_a.fs.create_dir("/b".as_ref()).await.unwrap();
|
client_a.fs.create_dir("/b".as_ref()).await.unwrap();
|
||||||
let (_project_b, _) = client_b.build_local_project("/b", cx_b).await;
|
let (_project_b, _) = client_b.build_local_project("/b", cx_b).await;
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![("a", vec!["user_b"])]),
|
]
|
||||||
("user_b", true, vec![("b", vec![])]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
(
|
||||||
)
|
"user_a".to_string(),
|
||||||
});
|
true,
|
||||||
}
|
vec![("a".to_string(), vec!["user_b".to_string()])]
|
||||||
|
),
|
||||||
|
("user_c".to_string(), true, vec![])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"user_a".to_string(),
|
||||||
|
true,
|
||||||
|
vec![("a".to_string(), vec!["user_b".to_string()])]
|
||||||
|
),
|
||||||
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
project_a
|
project_a
|
||||||
.condition(cx_a, |project, _| {
|
.condition(cx_a, |project, _| {
|
||||||
|
@ -3990,41 +4034,46 @@ async fn test_contacts(
|
||||||
|
|
||||||
cx_a.update(move |_| drop(project_a));
|
cx_a.update(move |_| drop(project_a));
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![]),
|
]
|
||||||
("user_b", true, vec![("b", vec![])]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
("user_a".to_string(), true, vec![]),
|
||||||
)
|
("user_c".to_string(), true, vec![])
|
||||||
});
|
]
|
||||||
}
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
("user_a".to_string(), true, vec![]),
|
||||||
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
server.disconnect_client(client_c.current_user_id(cx_c));
|
server.disconnect_client(client_c.current_user_id(cx_c));
|
||||||
server.forbid_connections();
|
server.forbid_connections();
|
||||||
deterministic.advance_clock(rpc::RECEIVE_TIMEOUT);
|
deterministic.advance_clock(rpc::RECEIVE_TIMEOUT);
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])]),
|
||||||
[
|
("user_c".to_string(), false, vec![])
|
||||||
("user_a", true, vec![]),
|
]
|
||||||
("user_b", true, vec![("b", vec![])]),
|
);
|
||||||
("user_c", false, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
("user_a".to_string(), true, vec![]),
|
||||||
)
|
("user_c".to_string(), false, vec![])
|
||||||
});
|
]
|
||||||
}
|
);
|
||||||
client_c
|
assert_eq!(contacts(&client_c, cx_c), []);
|
||||||
.user_store
|
|
||||||
.read_with(cx_c, |store, _| assert_eq!(contacts(store), []));
|
|
||||||
|
|
||||||
server.allow_connections();
|
server.allow_connections();
|
||||||
client_c
|
client_c
|
||||||
|
@ -4033,40 +4082,52 @@ async fn test_contacts(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
for (client, cx) in [(&client_a, &cx_a), (&client_b, &cx_b), (&client_c, &cx_c)] {
|
assert_eq!(
|
||||||
client.user_store.read_with(*cx, |store, _| {
|
contacts(&client_a, cx_a),
|
||||||
assert_eq!(
|
[
|
||||||
contacts(store),
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])]),
|
||||||
[
|
("user_c".to_string(), true, vec![])
|
||||||
("user_a", true, vec![]),
|
]
|
||||||
("user_b", true, vec![("b", vec![])]),
|
);
|
||||||
("user_c", true, vec![])
|
assert_eq!(
|
||||||
],
|
contacts(&client_b, cx_b),
|
||||||
"{} has the wrong contacts",
|
[
|
||||||
client.username
|
("user_a".to_string(), true, vec![]),
|
||||||
)
|
("user_c".to_string(), true, vec![])
|
||||||
});
|
]
|
||||||
}
|
);
|
||||||
|
assert_eq!(
|
||||||
|
contacts(&client_c, cx_c),
|
||||||
|
[
|
||||||
|
("user_a".to_string(), true, vec![]),
|
||||||
|
("user_b".to_string(), true, vec![("b".to_string(), vec![])])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn contacts(user_store: &UserStore) -> Vec<(&str, bool, Vec<(&str, Vec<&str>)>)> {
|
fn contacts(
|
||||||
user_store
|
client: &TestClient,
|
||||||
.contacts()
|
cx: &TestAppContext,
|
||||||
.iter()
|
) -> Vec<(String, bool, Vec<(String, Vec<String>)>)> {
|
||||||
.map(|contact| {
|
client.user_store.read_with(cx, |store, _| {
|
||||||
let projects = contact
|
store
|
||||||
.projects
|
.contacts()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| {
|
.map(|contact| {
|
||||||
(
|
let projects = contact
|
||||||
p.visible_worktree_root_names[0].as_str(),
|
.projects
|
||||||
p.guests.iter().map(|p| p.github_login.as_str()).collect(),
|
.iter()
|
||||||
)
|
.map(|p| {
|
||||||
})
|
(
|
||||||
.collect();
|
p.visible_worktree_root_names[0].clone(),
|
||||||
(contact.user.github_login.as_str(), contact.online, projects)
|
p.guests.iter().map(|p| p.github_login.clone()).collect(),
|
||||||
})
|
)
|
||||||
.collect()
|
})
|
||||||
|
.collect();
|
||||||
|
(contact.user.github_login.clone(), contact.online, projects)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4169,18 +4230,18 @@ async fn test_contact_requests(
|
||||||
|
|
||||||
// User B sees user A as their contact now in all client, and the incoming request from them is removed.
|
// User B sees user A as their contact now in all client, and the incoming request from them is removed.
|
||||||
let contacts_b = client_b.summarize_contacts(cx_b);
|
let contacts_b = client_b.summarize_contacts(cx_b);
|
||||||
assert_eq!(contacts_b.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_b.current, &["user_a"]);
|
||||||
assert_eq!(contacts_b.incoming_requests, &["user_c"]);
|
assert_eq!(contacts_b.incoming_requests, &["user_c"]);
|
||||||
let contacts_b2 = client_b2.summarize_contacts(cx_b2);
|
let contacts_b2 = client_b2.summarize_contacts(cx_b2);
|
||||||
assert_eq!(contacts_b2.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_b2.current, &["user_a"]);
|
||||||
assert_eq!(contacts_b2.incoming_requests, &["user_c"]);
|
assert_eq!(contacts_b2.incoming_requests, &["user_c"]);
|
||||||
|
|
||||||
// User A sees user B as their contact now in all clients, and the outgoing request to them is removed.
|
// User A sees user B as their contact now in all clients, and the outgoing request to them is removed.
|
||||||
let contacts_a = client_a.summarize_contacts(cx_a);
|
let contacts_a = client_a.summarize_contacts(cx_a);
|
||||||
assert_eq!(contacts_a.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_a.current, &["user_b"]);
|
||||||
assert!(contacts_a.outgoing_requests.is_empty());
|
assert!(contacts_a.outgoing_requests.is_empty());
|
||||||
let contacts_a2 = client_a2.summarize_contacts(cx_a2);
|
let contacts_a2 = client_a2.summarize_contacts(cx_a2);
|
||||||
assert_eq!(contacts_a2.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_a2.current, &["user_b"]);
|
||||||
assert!(contacts_a2.outgoing_requests.is_empty());
|
assert!(contacts_a2.outgoing_requests.is_empty());
|
||||||
|
|
||||||
// Contacts are present upon connecting (tested here via disconnect/reconnect)
|
// Contacts are present upon connecting (tested here via disconnect/reconnect)
|
||||||
|
@ -4188,19 +4249,13 @@ async fn test_contact_requests(
|
||||||
disconnect_and_reconnect(&client_b, cx_b).await;
|
disconnect_and_reconnect(&client_b, cx_b).await;
|
||||||
disconnect_and_reconnect(&client_c, cx_c).await;
|
disconnect_and_reconnect(&client_c, cx_c).await;
|
||||||
executor.run_until_parked();
|
executor.run_until_parked();
|
||||||
assert_eq!(
|
assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
|
||||||
client_a.summarize_contacts(cx_a).current,
|
assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
|
||||||
&["user_a", "user_b"]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
client_b.summarize_contacts(cx_b).current,
|
|
||||||
&["user_a", "user_b"]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client_b.summarize_contacts(cx_b).incoming_requests,
|
client_b.summarize_contacts(cx_b).incoming_requests,
|
||||||
&["user_c"]
|
&["user_c"]
|
||||||
);
|
);
|
||||||
assert_eq!(client_c.summarize_contacts(cx_c).current, &["user_c"]);
|
assert!(client_c.summarize_contacts(cx_c).current.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client_c.summarize_contacts(cx_c).outgoing_requests,
|
client_c.summarize_contacts(cx_c).outgoing_requests,
|
||||||
&["user_b"]
|
&["user_b"]
|
||||||
|
@ -4219,18 +4274,18 @@ async fn test_contact_requests(
|
||||||
|
|
||||||
// User B doesn't see user C as their contact, and the incoming request from them is removed.
|
// User B doesn't see user C as their contact, and the incoming request from them is removed.
|
||||||
let contacts_b = client_b.summarize_contacts(cx_b);
|
let contacts_b = client_b.summarize_contacts(cx_b);
|
||||||
assert_eq!(contacts_b.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_b.current, &["user_a"]);
|
||||||
assert!(contacts_b.incoming_requests.is_empty());
|
assert!(contacts_b.incoming_requests.is_empty());
|
||||||
let contacts_b2 = client_b2.summarize_contacts(cx_b2);
|
let contacts_b2 = client_b2.summarize_contacts(cx_b2);
|
||||||
assert_eq!(contacts_b2.current, &["user_a", "user_b"]);
|
assert_eq!(contacts_b2.current, &["user_a"]);
|
||||||
assert!(contacts_b2.incoming_requests.is_empty());
|
assert!(contacts_b2.incoming_requests.is_empty());
|
||||||
|
|
||||||
// User C doesn't see user B as their contact, and the outgoing request to them is removed.
|
// User C doesn't see user B as their contact, and the outgoing request to them is removed.
|
||||||
let contacts_c = client_c.summarize_contacts(cx_c);
|
let contacts_c = client_c.summarize_contacts(cx_c);
|
||||||
assert_eq!(contacts_c.current, &["user_c"]);
|
assert!(contacts_c.current.is_empty());
|
||||||
assert!(contacts_c.outgoing_requests.is_empty());
|
assert!(contacts_c.outgoing_requests.is_empty());
|
||||||
let contacts_c2 = client_c2.summarize_contacts(cx_c2);
|
let contacts_c2 = client_c2.summarize_contacts(cx_c2);
|
||||||
assert_eq!(contacts_c2.current, &["user_c"]);
|
assert!(contacts_c2.current.is_empty());
|
||||||
assert!(contacts_c2.outgoing_requests.is_empty());
|
assert!(contacts_c2.outgoing_requests.is_empty());
|
||||||
|
|
||||||
// Incoming/outgoing requests are not present upon connecting (tested here via disconnect/reconnect)
|
// Incoming/outgoing requests are not present upon connecting (tested here via disconnect/reconnect)
|
||||||
|
@ -4238,19 +4293,13 @@ async fn test_contact_requests(
|
||||||
disconnect_and_reconnect(&client_b, cx_b).await;
|
disconnect_and_reconnect(&client_b, cx_b).await;
|
||||||
disconnect_and_reconnect(&client_c, cx_c).await;
|
disconnect_and_reconnect(&client_c, cx_c).await;
|
||||||
executor.run_until_parked();
|
executor.run_until_parked();
|
||||||
assert_eq!(
|
assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
|
||||||
client_a.summarize_contacts(cx_a).current,
|
assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
|
||||||
&["user_a", "user_b"]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
client_b.summarize_contacts(cx_b).current,
|
|
||||||
&["user_a", "user_b"]
|
|
||||||
);
|
|
||||||
assert!(client_b
|
assert!(client_b
|
||||||
.summarize_contacts(cx_b)
|
.summarize_contacts(cx_b)
|
||||||
.incoming_requests
|
.incoming_requests
|
||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(client_c.summarize_contacts(cx_c).current, &["user_c"]);
|
assert!(client_c.summarize_contacts(cx_c).current.is_empty());
|
||||||
assert!(client_c
|
assert!(client_c
|
||||||
.summarize_contacts(cx_c)
|
.summarize_contacts(cx_c)
|
||||||
.outgoing_requests
|
.outgoing_requests
|
||||||
|
@ -5655,6 +5704,9 @@ impl TestClient {
|
||||||
worktree
|
worktree
|
||||||
.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
|
.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||||
.await;
|
.await;
|
||||||
|
project
|
||||||
|
.update(cx, |project, _| project.next_remote_id())
|
||||||
|
.await;
|
||||||
(project, worktree.read_with(cx, |tree, _| tree.id()))
|
(project, worktree.read_with(cx, |tree, _| tree.id()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,36 +298,21 @@ impl AddParticipantPopover {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_user = user_store.current_user();
|
|
||||||
|
|
||||||
let contacts = user_store.contacts();
|
let contacts = user_store.contacts();
|
||||||
if !contacts.is_empty() {
|
if !contacts.is_empty() {
|
||||||
// Always put the current user first.
|
// Always put the current user first.
|
||||||
self.match_candidates.clear();
|
self.match_candidates.clear();
|
||||||
self.match_candidates.reserve(contacts.len());
|
self.match_candidates
|
||||||
self.match_candidates.push(StringMatchCandidate {
|
.extend(
|
||||||
id: 0,
|
contacts
|
||||||
string: Default::default(),
|
.iter()
|
||||||
char_bag: Default::default(),
|
.enumerate()
|
||||||
});
|
.map(|(ix, contact)| StringMatchCandidate {
|
||||||
for (ix, contact) in contacts.iter().enumerate() {
|
id: ix,
|
||||||
let candidate = StringMatchCandidate {
|
string: contact.user.github_login.clone(),
|
||||||
id: ix,
|
char_bag: contact.user.github_login.chars().collect(),
|
||||||
string: contact.user.github_login.clone(),
|
}),
|
||||||
char_bag: contact.user.github_login.chars().collect(),
|
);
|
||||||
};
|
|
||||||
if current_user
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |current_user| current_user.id == contact.user.id)
|
|
||||||
{
|
|
||||||
self.match_candidates[0] = candidate;
|
|
||||||
} else {
|
|
||||||
self.match_candidates.push(candidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.match_candidates[0].string.is_empty() {
|
|
||||||
self.match_candidates.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let matches = executor.block(match_strings(
|
let matches = executor.block(match_strings(
|
||||||
&self.match_candidates,
|
&self.match_candidates,
|
||||||
|
|
|
@ -81,7 +81,6 @@ impl CollabTitlebarItem {
|
||||||
cx.subscribe(&view, |this, _, event, cx| {
|
cx.subscribe(&view, |this, _, event, cx| {
|
||||||
match event {
|
match event {
|
||||||
add_participant_popover::Event::Dismissed => {
|
add_participant_popover::Event::Dismissed => {
|
||||||
dbg!("dismissed");
|
|
||||||
this.add_participant_popover = None;
|
this.add_participant_popover = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue