Get basic test of accepting a contact request passing

This commit is contained in:
Nathan Sobo 2022-05-07 15:09:27 -06:00
parent 93dae88cac
commit 5d20338f69
5 changed files with 125 additions and 24 deletions

View file

@ -125,7 +125,7 @@ impl UserStore {
user_ids.insert(contact.user_id); user_ids.insert(contact.user_id);
user_ids.extend(contact.projects.iter().flat_map(|w| &w.guests).copied()); user_ids.extend(contact.projects.iter().flat_map(|w| &w.guests).copied());
} }
user_ids.extend(message.incoming_requests.iter().map(|req| req.user_id)); user_ids.extend(message.incoming_requests.iter().map(|req| req.requester_id));
user_ids.extend(message.outgoing_requests.iter()); user_ids.extend(message.outgoing_requests.iter());
let load_users = self.get_users(user_ids.into_iter().collect(), cx); let load_users = self.get_users(user_ids.into_iter().collect(), cx);
@ -144,7 +144,9 @@ impl UserStore {
let mut incoming_requests = Vec::new(); let mut incoming_requests = Vec::new();
for request in message.incoming_requests { for request in message.incoming_requests {
incoming_requests.push( incoming_requests.push(
this.update(&mut cx, |this, cx| this.fetch_user(request.user_id, cx)) this.update(&mut cx, |this, cx| {
this.fetch_user(request.requester_id, cx)
})
.await?, .await?,
); );
} }
@ -199,12 +201,20 @@ impl UserStore {
.is_ok() .is_ok()
} }
pub fn request_contact(&self, to_user_id: u64) -> impl Future<Output = Result<()>> { pub fn incoming_contact_requests(&self) -> &[Arc<User>] {
&self.incoming_contact_requests
}
pub fn outgoing_contact_requests(&self) -> &[Arc<User>] {
&self.outgoing_contact_requests
}
pub fn request_contact(&self, responder_id: u64) -> impl Future<Output = Result<()>> {
let client = self.client.upgrade(); let client = self.client.upgrade();
async move { async move {
client client
.ok_or_else(|| anyhow!("not logged in"))? .ok_or_else(|| anyhow!("not logged in"))?
.request(proto::RequestContact { to_user_id }) .request(proto::RequestContact { responder_id })
.await?; .await?;
Ok(()) Ok(())
} }
@ -212,7 +222,7 @@ impl UserStore {
pub fn respond_to_contact_request( pub fn respond_to_contact_request(
&self, &self,
from_user_id: u64, requester_id: u64,
accept: bool, accept: bool,
) -> impl Future<Output = Result<()>> { ) -> impl Future<Output = Result<()>> {
let client = self.client.upgrade(); let client = self.client.upgrade();
@ -220,7 +230,7 @@ impl UserStore {
client client
.ok_or_else(|| anyhow!("not logged in"))? .ok_or_else(|| anyhow!("not logged in"))?
.request(proto::RespondToContactRequest { .request(proto::RespondToContactRequest {
requesting_user_id: from_user_id, requester_id,
response: if accept { response: if accept {
proto::ContactRequestResponse::Accept proto::ContactRequestResponse::Accept
} else { } else {

View file

@ -211,7 +211,7 @@ impl Db for PostgresDb {
outgoing_requests.push(user_id_b); outgoing_requests.push(user_id_b);
} else { } else {
incoming_requests.push(IncomingContactRequest { incoming_requests.push(IncomingContactRequest {
requesting_user_id: user_id_b, requester_id: user_id_b,
should_notify, should_notify,
}); });
} }
@ -220,7 +220,7 @@ impl Db for PostgresDb {
current.push(user_id_a); current.push(user_id_a);
} else if a_to_b { } else if a_to_b {
incoming_requests.push(IncomingContactRequest { incoming_requests.push(IncomingContactRequest {
requesting_user_id: user_id_a, requester_id: user_id_a,
should_notify, should_notify,
}); });
} else { } else {
@ -675,7 +675,7 @@ pub struct Contacts {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct IncomingContactRequest { pub struct IncomingContactRequest {
pub requesting_user_id: UserId, pub requester_id: UserId,
pub should_notify: bool, pub should_notify: bool,
} }
@ -935,7 +935,7 @@ pub mod tests {
current: vec![], current: vec![],
outgoing_requests: vec![], outgoing_requests: vec![],
incoming_requests: vec![IncomingContactRequest { incoming_requests: vec![IncomingContactRequest {
requesting_user_id: user_1, requester_id: user_1,
should_notify: true should_notify: true
}], }],
}, },
@ -953,7 +953,7 @@ pub mod tests {
current: vec![], current: vec![],
outgoing_requests: vec![], outgoing_requests: vec![],
incoming_requests: vec![IncomingContactRequest { incoming_requests: vec![IncomingContactRequest {
requesting_user_id: user_1, requester_id: user_1,
should_notify: false should_notify: false
}], }],
}, },
@ -1195,7 +1195,7 @@ pub mod tests {
current.push(contact.requester_id); current.push(contact.requester_id);
} else { } else {
incoming_requests.push(IncomingContactRequest { incoming_requests.push(IncomingContactRequest {
requesting_user_id: contact.requester_id, requester_id: contact.requester_id,
should_notify: contact.should_notify, should_notify: contact.should_notify,
}); });
} }

View file

@ -276,7 +276,7 @@ impl Server {
store.add_connection(connection_id, user_id); store.add_connection(connection_id, user_id);
let update_contacts = store.build_initial_contacts_update(contacts); let update_contacts = store.build_initial_contacts_update(contacts);
for connection_id in store.connection_ids_for_user(user_id) { for connection_id in store.connection_ids_for_user(user_id) {
this.peer.send(connection_id, update_contacts.clone()); this.peer.send(connection_id, update_contacts.clone())?;
} }
} }
@ -953,11 +953,30 @@ impl Server {
.read() .read()
.await .await
.user_id_for_connection(request.sender_id)?; .user_id_for_connection(request.sender_id)?;
let responder_id = UserId::from_proto(request.payload.to_user_id); let responder_id = UserId::from_proto(request.payload.responder_id);
self.app_state self.app_state
.db .db
.send_contact_request(requester_id, responder_id) .send_contact_request(requester_id, responder_id)
.await?; .await?;
// Update outgoing contact requests of requester
let mut update = proto::UpdateContacts::default();
update.outgoing_requests.push(responder_id.to_proto());
for connection_id in self.store().await.connection_ids_for_user(requester_id) {
self.peer.send(connection_id, update.clone())?;
}
// Update incoming contact requests of responder
let mut update = proto::UpdateContacts::default();
update.incoming_requests.push(proto::IncomingContactRequest {
requester_id: requester_id.to_proto(),
should_notify: true,
});
for connection_id in self.store().await.connection_ids_for_user(responder_id) {
self.peer.send(connection_id, update.clone())?;
}
response.send(proto::Ack {})?; response.send(proto::Ack {})?;
Ok(()) Ok(())
} }
@ -972,15 +991,45 @@ impl Server {
.read() .read()
.await .await
.user_id_for_connection(request.sender_id)?; .user_id_for_connection(request.sender_id)?;
let requester_id = UserId::from_proto(request.payload.requesting_user_id); let requester_id = UserId::from_proto(request.payload.requester_id);
let accept = request.payload.response == proto::ContactRequestResponse::Accept as i32;
self.app_state self.app_state
.db .db
.respond_to_contact_request( .respond_to_contact_request(
responder_id, responder_id,
requester_id, requester_id,
request.payload.response == proto::ContactRequestResponse::Accept as i32, accept,
) )
.await?; .await?;
if accept {
// Update responder with new contact
let mut update = proto::UpdateContacts::default();
update.contacts.push(proto::Contact {
user_id: requester_id.to_proto(),
projects: Default::default(), // TODO
online: true, // TODO
});
update.remove_incoming_requests.push(requester_id.to_proto());
for connection_id in self.store.read().await.connection_ids_for_user(responder_id) {
self.peer.send(connection_id, update.clone())?;
}
// Update requester with new contact
let mut update = proto::UpdateContacts::default();
update.contacts.push(proto::Contact {
user_id: responder_id.to_proto(),
projects: Default::default(), // TODO
online: true, // TODO
});
update.remove_outgoing_requests.push(responder_id.to_proto());
for connection_id in self.store.read().await.connection_ids_for_user(requester_id) {
self.peer.send(connection_id, update.clone())?;
}
} else {
todo!()
}
response.send(proto::Ack {})?; response.send(proto::Ack {})?;
Ok(()) Ok(())
} }
@ -4987,8 +5036,8 @@ mod tests {
} }
} }
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 1)] // TODO: More iterations
async fn test_contacts_requests(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { async fn test_contacts_requests(executor: Arc<Deterministic>, cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking(); cx_a.foreground().forbid_parking();
// Connect to a server as 3 clients. // Connect to a server as 3 clients.
@ -4996,6 +5045,8 @@ mod tests {
let client_a = server.create_client(cx_a, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await; let client_b = server.create_client(cx_b, "user_b").await;
// User A requests that user B become their contact
client_a client_a
.user_store .user_store
.read_with(cx_a, |store, _| { .read_with(cx_a, |store, _| {
@ -5004,14 +5055,54 @@ mod tests {
.await .await
.unwrap(); .unwrap();
executor.run_until_parked();
// Both parties see the pending request appear. User B accepts the request.
client_a.user_store.read_with(cx_a, |store, _| {
let contacts = store
.outgoing_contact_requests()
.iter()
.map(|contact| contact.github_login.clone())
.collect::<Vec<_>>();
assert_eq!(contacts, &["user_b"]);
});
client_b.user_store.read_with(cx_b, |store, _| {
let contacts = store
.incoming_contact_requests()
.iter()
.map(|contact| contact.github_login.clone())
.collect::<Vec<_>>();
assert_eq!(contacts, &["user_a"]);
store.respond_to_contact_request(client_a.user_id().unwrap(), true)
}).await.unwrap();
executor.run_until_parked();
// User B sees user A as their contact now, and the incoming request from them is removed
client_b.user_store.read_with(cx_b, |store, _| {
let contacts = store
.contacts()
.iter()
.map(|contact| contact.user.github_login.clone())
.collect::<Vec<_>>();
assert_eq!(contacts, &["user_a"]);
assert!(store.incoming_contact_requests().is_empty());
});
// User A sees user B as their contact now, and the outgoing request to them is removed
client_a.user_store.read_with(cx_a, |store, _| { client_a.user_store.read_with(cx_a, |store, _| {
let contacts = store let contacts = store
.contacts() .contacts()
.iter() .iter()
.map(|contact| contact.user.github_login.clone()) .map(|contact| contact.user.github_login.clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(contacts, &["user_b"]) assert_eq!(contacts, &["user_b"]);
assert!(store.outgoing_contact_requests().is_empty());
}); });
} }
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 10)]

View file

@ -225,7 +225,7 @@ impl Store {
update update
.incoming_requests .incoming_requests
.push(proto::IncomingContactRequest { .push(proto::IncomingContactRequest {
user_id: request.requesting_user_id.to_proto(), requester_id: request.requester_id.to_proto(),
should_notify: request.should_notify, should_notify: request.should_notify,
}) })
} }

View file

@ -550,11 +550,11 @@ message UsersResponse {
} }
message RequestContact { message RequestContact {
uint64 to_user_id = 1; uint64 responder_id = 1;
} }
message RespondToContactRequest { message RespondToContactRequest {
uint64 requesting_user_id = 1; uint64 requester_id = 1;
ContactRequestResponse response = 2; ContactRequestResponse response = 2;
} }
@ -599,7 +599,7 @@ message UpdateContacts {
} }
message IncomingContactRequest { message IncomingContactRequest {
uint64 user_id = 1; uint64 requester_id = 1;
bool should_notify = 2; bool should_notify = 2;
} }