-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathdelete_user.ts
More file actions
157 lines (140 loc) · 4.61 KB
/
delete_user.ts
File metadata and controls
157 lines (140 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import admin from "firebase-admin";
import functions from "firebase-functions/v1";
import { HttpsError, onCall } from "firebase-functions/v2/https";
import { log } from "firebase-functions/logger";
const deleteUserDocument = async (
user: admin.auth.UserRecord
): Promise<void> => {
log(`deleteUserDocument: Deleting user document for: ${user.displayName}`);
try {
await admin.firestore().collection("users").doc(user.uid).delete();
} catch (error) {
log(
"error: " + JSON.stringify(error, Object.getOwnPropertyNames(error))
);
}
};
const deleteProfileDocument = async (
user: admin.auth.UserRecord
): Promise<void> => {
log(`deleteProfileDocument: Deleting profile for: ${user.displayName}`);
try {
await admin.firestore().collection("profiles").doc(user.uid).delete();
} catch (error) {
log(
"error: " + JSON.stringify(error, Object.getOwnPropertyNames(error))
);
}
};
const deleteUsernameDocument = async (
user: admin.auth.UserRecord
): Promise<void> => {
log(`deleteUsernameDocument: Deleting username of: ${user.displayName}`);
try {
const querySnapshot = await admin
.firestore()
.collection("usernames")
.where("userUid", "==", user.uid)
.get();
for (const doc of querySnapshot.docs) {
await admin.firestore().doc(doc.ref.path).delete();
}
} catch (error) {
log(
"error: " + JSON.stringify(error, Object.getOwnPropertyNames(error))
);
}
};
const deleteUserProjects = async (
user: admin.auth.UserRecord
): Promise<void> => {
log(`deleteProjects: Deleting projects created by: ${user.displayName}`);
const batch = admin.firestore().batch();
try {
const allProjectsRef = await admin
.firestore()
.collection("projects")
.where("userUid", "==", user.uid)
.get();
await Promise.all(
allProjectsRef.docs.map(async (doc) => {
const projectRef = admin.firestore().doc(doc.ref.path);
const projectSubcolls = await projectRef.listCollections();
for (const subcoll of projectSubcolls) {
const subcollDocs = await subcoll.get();
subcollDocs.forEach((subcollDoc) => {
batch.delete(subcollDoc.ref);
});
}
const projectLastModifiedRef = admin
.firestore()
.collection("projectLastModified")
.doc(projectRef.id);
batch.delete(projectLastModifiedRef);
batch.delete(projectRef);
})
);
await batch.commit();
} catch (error) {
log(
"error: " + JSON.stringify(error, Object.getOwnPropertyNames(error))
);
}
};
const deleteProjectsCount = async (
user: admin.auth.UserRecord
): Promise<void> => {
log(
`deleteProjectsCount: Deleting projectsCount for: ${user.displayName} under ${user.uid}`
);
try {
await admin
.firestore()
.collection("projectsCount")
.doc(user.uid)
.delete();
} catch (error) {
log(
"error: " + JSON.stringify(error, Object.getOwnPropertyNames(error))
);
}
};
const cleanupDeletedUserData = async (
user: admin.auth.UserRecord
): Promise<void> => {
await deleteUserProjects(user);
await deleteProfileDocument(user);
await deleteUserDocument(user);
await deleteUsernameDocument(user);
await deleteProjectsCount(user);
};
export const deleteAccount = onCall({ cors: true }, async (request) => {
const auth = request.auth;
if (!auth?.uid) {
throw new HttpsError("unauthenticated", "Authentication required.");
}
try {
const user = await admin.auth().getUser(auth.uid);
await cleanupDeletedUserData(user);
await admin.auth().deleteUser(auth.uid);
return { success: true };
} catch (error) {
log(
"deleteAccount error: " +
JSON.stringify(error, Object.getOwnPropertyNames(error || {}))
);
throw new HttpsError(
"internal",
"Failed to delete account and associated data."
);
}
});
export const deleteUserCallback = functions.auth
.user()
.onDelete(async (user) => {
log(
`deleteUserCallback: Removing user: ${user.displayName}, uid: ${user.uid}`
);
await cleanupDeletedUserData(user);
return true;
});