Skip to content

Commit 121f338

Browse files
Ehesplaurenzlong
authored andcommitted
[delete-user-data] Add new param for enabling recursive delete (#25)
1 parent 3de3dbe commit 121f338

File tree

9 files changed

+3468
-621
lines changed

9 files changed

+3468
-621
lines changed

delete-user-data/extension.yaml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
name: delete-user-data
1616
displayName: Delete User Data
1717
specVersion: v1beta
18-
version: 0.1.1
18+
version: 0.2.0
1919

2020
description:
2121
Deletes data keyed on a userId from Cloud Firestore, Realtime
@@ -36,9 +36,12 @@ contributors:
3636
- authorName: Chris Bianca
3737
email: chris@csfrequency.com
3838
url: https://github.com/chrisbianca
39+
- authorName: Elliot Hesp
40+
email: elliot@invertase.io
41+
url: https://github.com/ehesp
3942

4043
roles:
41-
- role: datastore.user
44+
- role: datastore.owner
4245
reason: Allows the extension to delete (user) data from Cloud Firestore.
4346
- role: firebasedatabase.admin
4447
reason: Allows the extension to delete (user) data from Realtime Database.
@@ -99,6 +102,20 @@ params:
99102
For example, if you have the collections `users` and `admins`, and each collection
100103
has documents with User ID as document IDs, then you can enter `users/{UID},admins/{UID}`.
101104
105+
- param: FIRESTORE_DELETE_MODE
106+
type: select
107+
label: Cloud Firestore delete mode
108+
description: >-
109+
How do you want to delete Cloud Firestore documents? To also delete documents in
110+
subcollections, set this parameter to `recursive`.
111+
options:
112+
- label: Recursive
113+
value: recursive
114+
- label: Shallow
115+
value: shallow
116+
default: shallow
117+
required: true
118+
102119
- param: RTDB_PATHS
103120
type: string
104121
label: Realtime Database paths

delete-user-data/functions/lib/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
*/
1717
Object.defineProperty(exports, "__esModule", { value: true });
1818
exports.default = {
19-
firestorePaths: process.env.FIRESTORE_PATHS,
2019
location: process.env.LOCATION,
20+
firestorePaths: process.env.FIRESTORE_PATHS,
21+
firestoreDeleteMode: process.env.FIRESTORE_DELETE_MODE,
2122
rtdbPaths: process.env.RTDB_PATHS,
2223
storagePaths: process.env.STORAGE_PATHS,
2324
};

delete-user-data/functions/lib/index.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
2525
Object.defineProperty(exports, "__esModule", { value: true });
2626
const admin = require("firebase-admin");
2727
const functions = require("firebase-functions");
28+
const firebase_tools = require("firebase-tools");
2829
const config_1 = require("./config");
2930
const logs = require("./logs");
3031
// Initialize the Firebase Admin SDK
@@ -113,12 +114,24 @@ const clearFirestoreData = (firestorePaths, uid) => __awaiter(this, void 0, void
113114
const paths = extractUserPaths(firestorePaths, uid);
114115
const promises = paths.map((path) => __awaiter(this, void 0, void 0, function* () {
115116
try {
116-
logs.firestorePathDeleting(path);
117-
yield admin
118-
.firestore()
119-
.doc(path)
120-
.delete();
121-
logs.firestorePathDeleted(path);
117+
const isRecursive = config_1.default.firestoreDeleteMode === 'recursive';
118+
if (!isRecursive) {
119+
logs.firestorePathDeleting(path, false);
120+
yield admin
121+
.firestore()
122+
.doc(path)
123+
.delete();
124+
logs.firestorePathDeleted(path, false);
125+
}
126+
else {
127+
logs.firestorePathDeleting(path, true);
128+
yield firebase_tools.firestore.delete(path, {
129+
project: process.env.PROJECT_ID,
130+
recursive: true,
131+
yes: true,
132+
});
133+
logs.firestorePathDeleted(path, true);
134+
}
122135
}
123136
catch (err) {
124137
logs.firestorePathError(path, err);

delete-user-data/functions/lib/logs.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ exports.firestoreDeleting = () => {
2828
exports.firestoreNotConfigured = () => {
2929
console.log("Cloud Firestore paths are not configured, skipping");
3030
};
31-
exports.firestorePathDeleted = (path) => {
32-
console.log(`Deleted: '${path}' from Cloud Firestore`);
31+
exports.firestorePathDeleted = (path, recursive) => {
32+
console.log(`Deleted: '${path}' from Cloud Firestore ${recursive ? 'with recursive delete' : ''}`);
3333
};
34-
exports.firestorePathDeleting = (path) => {
35-
console.log(`Deleting: '${path}' from Cloud Firestore`);
34+
exports.firestorePathDeleting = (path, recursive) => {
35+
console.log(`Deleting: '${path}' from Cloud Firestore ${recursive ? 'with recursive delete' : ''}`);
3636
};
3737
exports.firestorePathError = (path, err) => {
3838
console.error(`Error when deleting: '${path}' from Cloud Firestore`, err);

delete-user-data/functions/src/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
*/
1616

1717
export default {
18-
firestorePaths: process.env.FIRESTORE_PATHS,
1918
location: process.env.LOCATION,
19+
firestorePaths: process.env.FIRESTORE_PATHS,
20+
firestoreDeleteMode: process.env.FIRESTORE_DELETE_MODE,
2021
rtdbPaths: process.env.RTDB_PATHS,
2122
storagePaths: process.env.STORAGE_PATHS,
2223
};

delete-user-data/functions/src/index.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import * as admin from "firebase-admin";
1818
import * as functions from "firebase-functions";
19+
import * as firebase_tools from "firebase-tools";
1920

2021
import config from "./config";
2122
import * as logs from "./logs";
@@ -117,12 +118,24 @@ const clearFirestoreData = async (firestorePaths: string, uid: string) => {
117118
const paths = extractUserPaths(firestorePaths, uid);
118119
const promises = paths.map(async (path) => {
119120
try {
120-
logs.firestorePathDeleting(path);
121-
await admin
122-
.firestore()
123-
.doc(path)
124-
.delete();
125-
logs.firestorePathDeleted(path);
121+
const isRecursive = config.firestoreDeleteMode === 'recursive';
122+
123+
if (!isRecursive) {
124+
logs.firestorePathDeleting(path, false);
125+
await admin
126+
.firestore()
127+
.doc(path)
128+
.delete();
129+
logs.firestorePathDeleted(path, false);
130+
} else {
131+
logs.firestorePathDeleting(path, true);
132+
await firebase_tools.firestore.delete(path, {
133+
project: process.env.PROJECT_ID,
134+
recursive: true,
135+
yes: true, // auto-confirmation
136+
});
137+
logs.firestorePathDeleted(path, true);
138+
}
126139
} catch (err) {
127140
logs.firestorePathError(path, err);
128141
}

delete-user-data/functions/src/logs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ export const firestoreNotConfigured = () => {
3232
console.log("Cloud Firestore paths are not configured, skipping");
3333
};
3434

35-
export const firestorePathDeleted = (path: string) => {
36-
console.log(`Deleted: '${path}' from Cloud Firestore`);
35+
export const firestorePathDeleted = (path: string, recursive: boolean) => {
36+
console.log(`Deleted: '${path}' from Cloud Firestore ${recursive ? 'with recursive delete' : ''}`);
3737
};
3838

39-
export const firestorePathDeleting = (path: string) => {
40-
console.log(`Deleting: '${path}' from Cloud Firestore`);
39+
export const firestorePathDeleting = (path: string, recursive: boolean) => {
40+
console.log(`Deleting: '${path}' from Cloud Firestore ${recursive ? 'with recursive delete' : ''}`);
4141
};
4242

4343
export const firestorePathError = (path: string, err: Error) => {

0 commit comments

Comments
 (0)