Skip to content

Commit 9a51d84

Browse files
committed
Fix devices beeing removed completly when a user deletes their account
Fixes #224
1 parent 4cd9b01 commit 9a51d84

File tree

1 file changed

+91
-27
lines changed

1 file changed

+91
-27
lines changed

backend/src/routes/user/delete.rs

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
routes::{
1010
auth::login::{validate_password, FindBy},
1111
charger::remove::{
12-
delete_all_allowed_users, delete_all_keys, delete_charger, remove_charger_from_state,
12+
delete_charger, remove_charger_from_state,
1313
},
1414
user::logout::delete_all_refresh_tokens,
1515
},
@@ -77,26 +77,75 @@ pub async fn delete_user(
7777
user_id: crate::models::uuid::Uuid,
7878
payload: web::Json<DeleteUserSchema>,
7979
) -> actix_web::Result<impl Responder> {
80-
let user_id = user_id.into();
80+
let uid = user_id.into();
8181

8282
let conn = get_connection(&state)?;
83-
let _ = validate_password(&payload.login_key, FindBy::Uuid(user_id), conn).await?;
84-
85-
let chargers = get_all_chargers_for_user(user_id, &state).await?;
86-
let charger_ids: Vec<uuid::Uuid> = chargers.into_iter().map(|c| c.id).collect();
87-
for id in charger_ids.into_iter() {
88-
delete_all_keys(id, &state).await?;
89-
delete_all_allowed_users(id, &state).await?;
90-
delete_charger(id, &state).await?;
91-
remove_charger_from_state(id, &bridge_state).await;
83+
let _ = validate_password(&payload.login_key, FindBy::Uuid(uid), conn).await?;
84+
85+
let chargers = get_all_chargers_for_user(uid, &state).await?;
86+
let charger_ids: Vec<uuid::Uuid> = chargers.iter().map(|c| c.id).collect();
87+
for cid in charger_ids.into_iter() {
88+
// Remove user from allowed_users for this charger
89+
{
90+
let mut conn = get_connection(&state)?;
91+
crate::utils::web_block_unpacked(move || {
92+
use db_connector::schema::allowed_users::dsl::*;
93+
match diesel::delete(
94+
allowed_users
95+
.filter(user_id.eq(uid))
96+
.filter(charger_id.eq(cid)),
97+
)
98+
.execute(&mut conn)
99+
{
100+
Ok(_) => Ok(()),
101+
Err(_err) => Err(Error::InternalError),
102+
}
103+
})
104+
.await?;
105+
}
106+
// Remove user's keys for this charger
107+
{
108+
let mut conn = get_connection(&state)?;
109+
crate::utils::web_block_unpacked(move || {
110+
use db_connector::schema::wg_keys::dsl::*;
111+
match diesel::delete(wg_keys.filter(user_id.eq(uid)).filter(charger_id.eq(cid)))
112+
.execute(&mut conn)
113+
{
114+
Ok(_) => Ok(()),
115+
Err(_err) => Err(Error::InternalError),
116+
}
117+
})
118+
.await?;
119+
}
120+
// Check if any allowed users remain for this charger
121+
let allowed_count = {
122+
let mut conn = get_connection(&state)?;
123+
crate::utils::web_block_unpacked(move || {
124+
use db_connector::schema::allowed_users::dsl::*;
125+
match allowed_users
126+
.filter(charger_id.eq(cid))
127+
.count()
128+
.get_result::<i64>(&mut conn)
129+
{
130+
Ok(c) => Ok(c),
131+
Err(_err) => Err(Error::InternalError),
132+
}
133+
})
134+
.await?
135+
};
136+
println!("allowed_count: {allowed_count}");
137+
if allowed_count == 0 {
138+
delete_charger(cid, &state).await?;
139+
remove_charger_from_state(cid, &bridge_state).await;
140+
}
92141
}
93142

94-
delete_all_refresh_tokens(user_id, &state).await?;
143+
delete_all_refresh_tokens(uid, &state).await?;
95144
let mut conn = get_connection(&state)?;
96145
web_block_unpacked(move || {
97146
use db_connector::schema::users::dsl::*;
98147

99-
match diesel::delete(users.find(user_id)).execute(&mut conn) {
148+
match diesel::delete(users.find(uid)).execute(&mut conn) {
100149
Ok(_) => Ok(()),
101150
Err(_err) => {
102151
println!("err: {_err:?}");
@@ -114,6 +163,7 @@ mod tests {
114163
use std::str::FromStr;
115164

116165
use actix_web::{cookie::Cookie, test, App};
166+
use base64::Engine;
117167
use db_connector::{
118168
models::{allowed_users::AllowedUser, chargers::Charger, users::User, wg_keys::WgKey},
119169
test_connection_pool,
@@ -132,7 +182,6 @@ mod tests {
132182

133183
use super::{delete_user, DeleteUserSchema};
134184

135-
//TODO: add test for shared charger once it is merged
136185
#[actix_web::test]
137186
async fn test_delete() {
138187
let (mut user1, user1_mail) = TestUser::random().await;
@@ -141,6 +190,11 @@ mod tests {
141190
user2.login().await;
142191
let charger = user1.add_random_charger().await;
143192
let charger2 = user2.add_random_charger().await;
193+
// Share charger with user2
194+
let user2_auth = crate::routes::charger::allow_user::UserAuth::LoginKey(
195+
base64::prelude::BASE64_STANDARD.encode(&user2.get_login_key().await),
196+
);
197+
user1.allow_user(&user2_mail, user2_auth, &charger).await;
144198
let uid1 = get_test_uuid(&user1_mail).unwrap();
145199
let uid2 = get_test_uuid(&user2_mail).unwrap();
146200

@@ -168,28 +222,37 @@ mod tests {
168222
{
169223
use db_connector::schema::allowed_users::dsl::*;
170224

225+
// user1 should be gone
171226
let res = allowed_users
172227
.filter(user_id.eq(uid1))
173228
.select(AllowedUser::as_select())
174229
.get_result(&mut conn);
175230
assert_eq!(res, Err(NotFound));
176231

232+
// user2 should still have access to both chargers
177233
let res = allowed_users
178234
.filter(user_id.eq(uid2))
179235
.select(AllowedUser::as_select())
180-
.get_result(&mut conn);
181-
assert!(res.is_ok());
236+
.load::<AllowedUser>(&mut conn);
237+
let charger_ids: Vec<uuid::Uuid> =
238+
res.unwrap().into_iter().map(|au| au.charger_id).collect();
239+
let uuid = uuid::Uuid::from_str(&charger.uuid).unwrap();
240+
let uuid2 = uuid::Uuid::from_str(&charger2.uuid).unwrap();
241+
println!("charger_ids: {charger_ids:?}");
242+
assert!(charger_ids.contains(&uuid));
243+
assert!(charger_ids.contains(&uuid2));
182244
}
183245
let uuid = uuid::Uuid::from_str(&charger.uuid).unwrap();
184246
let uuid2 = uuid::Uuid::from_str(&charger2.uuid).unwrap();
185247
{
186248
use db_connector::schema::chargers::dsl::*;
187249

250+
// Both chargers should still exist
188251
let res = chargers
189252
.filter(id.eq(uuid))
190253
.select(Charger::as_select())
191254
.get_result(&mut conn);
192-
assert_eq!(res, Err(NotFound));
255+
assert!(res.is_ok());
193256

194257
let res = chargers
195258
.filter(id.eq(uuid2))
@@ -200,22 +263,23 @@ mod tests {
200263
{
201264
use db_connector::schema::wg_keys::dsl::*;
202265

266+
// Only user2's keys should remain for both chargers
203267
let uuid = uuid::Uuid::from_str(&charger.uuid).unwrap();
204-
let res = wg_keys
205-
.filter(charger_id.eq(uuid))
268+
let uuid2 = uuid::Uuid::from_str(&charger2.uuid).unwrap();
269+
let keys_user2: Vec<_> = wg_keys
270+
.filter(charger_id.eq(uuid).or(charger_id.eq(uuid2)))
206271
.select(WgKey::as_select())
207-
.get_result(&mut conn);
208-
assert_eq!(res, Err(NotFound));
209-
210-
let res = wg_keys
211-
.filter(charger_id.eq(uuid2))
212-
.select(WgKey::as_select())
213-
.get_result(&mut conn);
214-
assert!(res.is_ok());
272+
.load::<WgKey>(&mut conn)
273+
.unwrap()
274+
.into_iter()
275+
.filter(|k| k.user_id == uid2)
276+
.collect();
277+
assert!(!keys_user2.is_empty());
215278
}
216279
{
217280
use db_connector::schema::users::dsl::*;
218281

282+
// user1 should be deleted, user2 should remain
219283
let res = users
220284
.find(uid1)
221285
.select(User::as_select())

0 commit comments

Comments
 (0)