@@ -6,13 +6,15 @@ import com.supercilex.robotscouter.common.FIRESTORE_BASE_TIMESTAMP
6
6
import com.supercilex.robotscouter.common.FIRESTORE_CONTENT_ID
7
7
import com.supercilex.robotscouter.common.FIRESTORE_LAST_LOGIN
8
8
import com.supercilex.robotscouter.common.FIRESTORE_METRICS
9
+ import com.supercilex.robotscouter.common.FIRESTORE_NAME
9
10
import com.supercilex.robotscouter.common.FIRESTORE_OWNERS
10
11
import com.supercilex.robotscouter.common.FIRESTORE_SCOUTS
11
12
import com.supercilex.robotscouter.common.FIRESTORE_SHARE_TYPE
12
13
import com.supercilex.robotscouter.common.FIRESTORE_TIMESTAMP
13
14
import com.supercilex.robotscouter.common.FIRESTORE_TYPE
14
15
import com.supercilex.robotscouter.server.utils.FIRESTORE_EMAIL
15
16
import com.supercilex.robotscouter.server.utils.FIRESTORE_PHONE_NUMBER
17
+ import com.supercilex.robotscouter.server.utils.FIRESTORE_PHOTO_URL
16
18
import com.supercilex.robotscouter.server.utils.auth
17
19
import com.supercilex.robotscouter.server.utils.batch
18
20
import com.supercilex.robotscouter.server.utils.delete
@@ -51,6 +53,7 @@ import kotlinx.coroutines.asPromise
51
53
import kotlinx.coroutines.async
52
54
import kotlinx.coroutines.await
53
55
import kotlinx.coroutines.awaitAll
56
+ import kotlinx.coroutines.coroutineScope
54
57
import kotlinx.coroutines.delay
55
58
import kotlinx.coroutines.joinAll
56
59
import kotlinx.coroutines.launch
@@ -75,7 +78,7 @@ fun deleteUnusedData(): Promise<*>? = GlobalScope.async {
75
78
))
76
79
}
77
80
val anonymousUser = async {
78
- deleteUnusedData (users.where(
81
+ deleteAnonymousUsers (users.where(
79
82
FIRESTORE_LAST_LOGIN ,
80
83
" <" ,
81
84
Timestamps .fromDate(
@@ -142,9 +145,37 @@ fun sanitizeDeletionRequest(event: Change<DeltaDocumentSnapshot>): Promise<*>? {
142
145
}
143
146
}
144
147
145
- private suspend fun CoroutineScope.deleteUnusedData (
148
+ private suspend fun deleteAnonymousUsers (
149
+ userQuery : Query
150
+ ) = userQuery.processInBatches(10 ) { user ->
151
+ val userRecord = try {
152
+ auth.getUser(user.id).await()
153
+ } catch (t: Throwable ) {
154
+ if (t.asDynamic().code != " auth/user-not-found" ) throw t else null
155
+ }
156
+
157
+ if (userRecord == null || userRecord.providerData.orEmpty().isEmpty()) {
158
+ purgeUser(user)
159
+ } else {
160
+ console.log(" Correcting user inadvertently marked as anonymous: " +
161
+ JSON .stringify(userRecord.toJSON()))
162
+
163
+ val payload = json()
164
+ userRecord.email?.let { payload[FIRESTORE_EMAIL ] = it }
165
+ userRecord.displayName?.let { payload[FIRESTORE_NAME ] = it }
166
+ userRecord.phoneNumber?.let { payload[FIRESTORE_PHONE_NUMBER ] = it }
167
+ userRecord.photoURL?.let { payload[FIRESTORE_PHOTO_URL ] = it }
168
+ user.ref.set(payload, SetOptions .merge).await()
169
+ }
170
+ }
171
+
172
+ private suspend fun deleteUnusedData (
146
173
userQuery : Query
147
174
) = userQuery.processInBatches(10 ) { user ->
175
+ purgeUser(user)
176
+ }
177
+
178
+ private suspend fun purgeUser (user : DocumentSnapshot ) = coroutineScope {
148
179
console.log(" Deleting all data for user:\n ${JSON .stringify(user.data())} " )
149
180
150
181
val userId = user.id
@@ -264,8 +295,7 @@ private suspend fun deleteUser(user: DocumentSnapshot) {
264
295
try {
265
296
auth.deleteUser(user.id).await()
266
297
} catch (t: Throwable ) {
267
- @Suppress(" UNCHECKED_CAST_TO_EXTERNAL_INTERFACE" ) // It's a JS object
268
- if ((t as Json )[" code" ] != " auth/user-not-found" ) throw t
298
+ if (t.asDynamic().code != " auth/user-not-found" ) throw t
269
299
}
270
300
271
301
deletionQueue.doc(user.id).delete().await()
0 commit comments