So I'm trying to make sure a set of async tasks get executed in a specific order when a user is being deleted.
So what I want to happen is :
- Check if user has added guests with their purchase
- if user has no guests or any purchases at all, return from the function and continue with deletion process (bullet point 6)
- if user has guests for any of their purchases, delete every single guest
- once all the guests are deleted, go ahead and delete every purchase they made
- once all purchases made are deleted, go ahead and delete the actual user itself out of Firestore
- 2 seconds after that, I delete the user out of firebase auth just to make sure there are no crashes trying to delete documents with an empty user
- then I simply segue to the main menu
So I'm trying to accomplish this with this block of code in my function:
let deleteAction = UIAlertAction(title: "Delete", style: .destructive) { (deletion) in
let semaphore = DispatchSemaphore(value: 0)
self.deleteButton.isHidden = true
self.loadingToDelete.alpha = 1
self.loadingToDelete.startAnimating()
DispatchQueue.global(qos: .background).async {
self.db.collection("student_users/\(user.uid)/events_bought").getDocuments { (querySnapshot, error) in
guard error == nil else {
print("The docs couldn't be retrieved for deletion.")
return
}
guard querySnapshot?.isEmpty == false else {
print("The user being deleted has no events purchased.")
return
}
for document in querySnapshot!.documents {
let docID = document.documentID
self.db.collection("student_users/\(user.uid)/events_bought/\(docID)/guests").getDocuments { (querySnap, error) in
guard querySnap?.isEmpty == false else {
print("The user being deleted has no guests with his purchases.")
return
}
for doc in querySnap!.documents {
let guest = doc.documentID
self.db.document("student_users/\(user.uid)/events_bought/\(docID)/guests/\(guest)").delete { (error) in
guard error == nil else {
print("Error deleting guests while deleting user.")
return
}
print("Guests deleted while deleting user!")
semaphore.signal()
}
semaphore.wait()
}
}
}
}
self.db.collection("student_users/\(user.uid)/events_bought").getDocuments { (querySnapshot, error) in
guard error == nil else {
print("There was an error retrieving docs for user deletion.")
return
}
guard querySnapshot?.isEmpty == false else {
return
}
for document in querySnapshot!.documents {
let docID = document.documentID
self.db.document("student_users/\(user.uid)/events_bought/\(docID)").delete { (err) in
guard err == nil else {
print("There was an error deleting the the purchased events for the user being deleted.")
return
}
print("Purchases have been deleted for deleted user!")
semaphore.signal()
}
semaphore.wait()
}
}
self.db.document("student_users/\(user.uid)").delete(completion: { (error) in
guard error == nil else {
print("There was an error deleting the user document.")
return
}
print("User doc deleted!")
semaphore.signal()
})
semaphore.wait()
}
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
user.delete(completion: { (error) in
guard error == nil else {
print("There was an error deleting user from the system.")
return
}
print("User Deleted.")
})
}
self.loadingToDelete.stopAnimating()
self.performSegue(withIdentifier: Constants.Segues.studentUserDeletedAccount, sender: self)
}
I've been trying to play around with DispatchSemaphore()
for the last couple of hours and implement it into my code, but it just doesn't do what I expect it to do. I would read up on articles and examples of DispatchSemaphore()
online but the scenarios aren't exactly the same as mine in regards to what I specifically want to do.
When this alert action gets triggered on tap, nothing prints, and it just ends up spinning forever, the user isn't deleted out of Firebase Auth and there is still leftover data in the Firestore database like so:
I just basically want to figure out the best way to order these async tasks in the ordered list above and have a clean user deletion with no leftover in the database. Thanks in advance.