1use super::*;
2
3impl Database {
4 pub async fn get_contacts(&self, user_id: UserId) -> Result<Vec<Contact>> {
5 #[derive(Debug, FromQueryResult)]
6 struct ContactWithUserBusyStatuses {
7 user_id_a: UserId,
8 user_id_b: UserId,
9 a_to_b: bool,
10 accepted: bool,
11 should_notify: bool,
12 user_a_busy: bool,
13 user_b_busy: bool,
14 }
15
16 self.transaction(|tx| async move {
17 let user_a_participant = Alias::new("user_a_participant");
18 let user_b_participant = Alias::new("user_b_participant");
19 let mut db_contacts = contact::Entity::find()
20 .column_as(
21 Expr::tbl(user_a_participant.clone(), room_participant::Column::Id)
22 .is_not_null(),
23 "user_a_busy",
24 )
25 .column_as(
26 Expr::tbl(user_b_participant.clone(), room_participant::Column::Id)
27 .is_not_null(),
28 "user_b_busy",
29 )
30 .filter(
31 contact::Column::UserIdA
32 .eq(user_id)
33 .or(contact::Column::UserIdB.eq(user_id)),
34 )
35 .join_as(
36 JoinType::LeftJoin,
37 contact::Relation::UserARoomParticipant.def(),
38 user_a_participant,
39 )
40 .join_as(
41 JoinType::LeftJoin,
42 contact::Relation::UserBRoomParticipant.def(),
43 user_b_participant,
44 )
45 .into_model::<ContactWithUserBusyStatuses>()
46 .stream(&*tx)
47 .await?;
48
49 let mut contacts = Vec::new();
50 while let Some(db_contact) = db_contacts.next().await {
51 let db_contact = db_contact?;
52 if db_contact.user_id_a == user_id {
53 if db_contact.accepted {
54 contacts.push(Contact::Accepted {
55 user_id: db_contact.user_id_b,
56 should_notify: db_contact.should_notify && db_contact.a_to_b,
57 busy: db_contact.user_b_busy,
58 });
59 } else if db_contact.a_to_b {
60 contacts.push(Contact::Outgoing {
61 user_id: db_contact.user_id_b,
62 })
63 } else {
64 contacts.push(Contact::Incoming {
65 user_id: db_contact.user_id_b,
66 should_notify: db_contact.should_notify,
67 });
68 }
69 } else if db_contact.accepted {
70 contacts.push(Contact::Accepted {
71 user_id: db_contact.user_id_a,
72 should_notify: db_contact.should_notify && !db_contact.a_to_b,
73 busy: db_contact.user_a_busy,
74 });
75 } else if db_contact.a_to_b {
76 contacts.push(Contact::Incoming {
77 user_id: db_contact.user_id_a,
78 should_notify: db_contact.should_notify,
79 });
80 } else {
81 contacts.push(Contact::Outgoing {
82 user_id: db_contact.user_id_a,
83 });
84 }
85 }
86
87 contacts.sort_unstable_by_key(|contact| contact.user_id());
88
89 Ok(contacts)
90 })
91 .await
92 }
93
94 pub async fn is_user_busy(&self, user_id: UserId) -> Result<bool> {
95 self.transaction(|tx| async move {
96 let participant = room_participant::Entity::find()
97 .filter(room_participant::Column::UserId.eq(user_id))
98 .one(&*tx)
99 .await?;
100 Ok(participant.is_some())
101 })
102 .await
103 }
104
105 pub async fn has_contact(&self, user_id_1: UserId, user_id_2: UserId) -> Result<bool> {
106 self.transaction(|tx| async move {
107 let (id_a, id_b) = if user_id_1 < user_id_2 {
108 (user_id_1, user_id_2)
109 } else {
110 (user_id_2, user_id_1)
111 };
112
113 Ok(contact::Entity::find()
114 .filter(
115 contact::Column::UserIdA
116 .eq(id_a)
117 .and(contact::Column::UserIdB.eq(id_b))
118 .and(contact::Column::Accepted.eq(true)),
119 )
120 .one(&*tx)
121 .await?
122 .is_some())
123 })
124 .await
125 }
126
127 pub async fn send_contact_request(&self, sender_id: UserId, receiver_id: UserId) -> Result<()> {
128 self.transaction(|tx| async move {
129 let (id_a, id_b, a_to_b) = if sender_id < receiver_id {
130 (sender_id, receiver_id, true)
131 } else {
132 (receiver_id, sender_id, false)
133 };
134
135 let rows_affected = contact::Entity::insert(contact::ActiveModel {
136 user_id_a: ActiveValue::set(id_a),
137 user_id_b: ActiveValue::set(id_b),
138 a_to_b: ActiveValue::set(a_to_b),
139 accepted: ActiveValue::set(false),
140 should_notify: ActiveValue::set(true),
141 ..Default::default()
142 })
143 .on_conflict(
144 OnConflict::columns([contact::Column::UserIdA, contact::Column::UserIdB])
145 .values([
146 (contact::Column::Accepted, true.into()),
147 (contact::Column::ShouldNotify, false.into()),
148 ])
149 .action_and_where(
150 contact::Column::Accepted.eq(false).and(
151 contact::Column::AToB
152 .eq(a_to_b)
153 .and(contact::Column::UserIdA.eq(id_b))
154 .or(contact::Column::AToB
155 .ne(a_to_b)
156 .and(contact::Column::UserIdA.eq(id_a))),
157 ),
158 )
159 .to_owned(),
160 )
161 .exec_without_returning(&*tx)
162 .await?;
163
164 if rows_affected == 1 {
165 Ok(())
166 } else {
167 Err(anyhow!("contact already requested"))?
168 }
169 })
170 .await
171 }
172
173 /// Returns a bool indicating whether the removed contact had originally accepted or not
174 ///
175 /// Deletes the contact identified by the requester and responder ids, and then returns
176 /// whether the deleted contact had originally accepted or was a pending contact request.
177 ///
178 /// # Arguments
179 ///
180 /// * `requester_id` - The user that initiates this request
181 /// * `responder_id` - The user that will be removed
182 pub async fn remove_contact(&self, requester_id: UserId, responder_id: UserId) -> Result<bool> {
183 self.transaction(|tx| async move {
184 let (id_a, id_b) = if responder_id < requester_id {
185 (responder_id, requester_id)
186 } else {
187 (requester_id, responder_id)
188 };
189
190 let contact = contact::Entity::find()
191 .filter(
192 contact::Column::UserIdA
193 .eq(id_a)
194 .and(contact::Column::UserIdB.eq(id_b)),
195 )
196 .one(&*tx)
197 .await?
198 .ok_or_else(|| anyhow!("no such contact"))?;
199
200 contact::Entity::delete_by_id(contact.id).exec(&*tx).await?;
201 Ok(contact.accepted)
202 })
203 .await
204 }
205
206 pub async fn dismiss_contact_notification(
207 &self,
208 user_id: UserId,
209 contact_user_id: UserId,
210 ) -> Result<()> {
211 self.transaction(|tx| async move {
212 let (id_a, id_b, a_to_b) = if user_id < contact_user_id {
213 (user_id, contact_user_id, true)
214 } else {
215 (contact_user_id, user_id, false)
216 };
217
218 let result = contact::Entity::update_many()
219 .set(contact::ActiveModel {
220 should_notify: ActiveValue::set(false),
221 ..Default::default()
222 })
223 .filter(
224 contact::Column::UserIdA
225 .eq(id_a)
226 .and(contact::Column::UserIdB.eq(id_b))
227 .and(
228 contact::Column::AToB
229 .eq(a_to_b)
230 .and(contact::Column::Accepted.eq(true))
231 .or(contact::Column::AToB
232 .ne(a_to_b)
233 .and(contact::Column::Accepted.eq(false))),
234 ),
235 )
236 .exec(&*tx)
237 .await?;
238 if result.rows_affected == 0 {
239 Err(anyhow!("no such contact request"))?
240 } else {
241 Ok(())
242 }
243 })
244 .await
245 }
246
247 pub async fn respond_to_contact_request(
248 &self,
249 responder_id: UserId,
250 requester_id: UserId,
251 accept: bool,
252 ) -> Result<()> {
253 self.transaction(|tx| async move {
254 let (id_a, id_b, a_to_b) = if responder_id < requester_id {
255 (responder_id, requester_id, false)
256 } else {
257 (requester_id, responder_id, true)
258 };
259 let rows_affected = if accept {
260 let result = contact::Entity::update_many()
261 .set(contact::ActiveModel {
262 accepted: ActiveValue::set(true),
263 should_notify: ActiveValue::set(true),
264 ..Default::default()
265 })
266 .filter(
267 contact::Column::UserIdA
268 .eq(id_a)
269 .and(contact::Column::UserIdB.eq(id_b))
270 .and(contact::Column::AToB.eq(a_to_b)),
271 )
272 .exec(&*tx)
273 .await?;
274 result.rows_affected
275 } else {
276 let result = contact::Entity::delete_many()
277 .filter(
278 contact::Column::UserIdA
279 .eq(id_a)
280 .and(contact::Column::UserIdB.eq(id_b))
281 .and(contact::Column::AToB.eq(a_to_b))
282 .and(contact::Column::Accepted.eq(false)),
283 )
284 .exec(&*tx)
285 .await?;
286
287 result.rows_affected
288 };
289
290 if rows_affected == 1 {
291 Ok(())
292 } else {
293 Err(anyhow!("no such contact request"))?
294 }
295 })
296 .await
297 }
298}