Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _emulator/extensions/delete-user-data.env.local
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
LOCATION=europe-west2
FIRESTORE_QUERY_COLLECTION=queries
ENABLE_AUTO_DISCOVERY=true
AUTO_DISCOVERY_SEARCH_FIELDS=field1,field2
AUTO_DISCOVERY_SEARCH_FIELDS=field1,field2,scope.owner.id
SEARCH_FUNCTION=http://127.0.0.1:5001/demo-test/us-central1/findDocumentReferences
AUTO_DISCOVERY_TOPIC=discovery
AUTO_DISCOVERY_SEARCH_DEPTH=4
Expand Down
21 changes: 21 additions & 0 deletions delete-user-data/functions/__tests__/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ describe("discovery", () => {
await waitForDocumentDeletion(document, 60000);
}, 60000);

test("can delete a document with a nested field value matching {uid}", async () => {
const document = await db
.collection(generateRandomId())
.add({ scope: { owner: { id: user.uid } } });
await search(user.uid, 1, db);

await waitForDocumentDeletion(document, 60000);
}, 60000);

test("cannot delete a document with a nested field value that does not match {uid}", async () => {
const document = await db
.collection(generateRandomId())
.add({ scope: { owner: { id: "not-the-uid" } } });
await search(user.uid, 1, db);

await new Promise((resolve) => setTimeout(resolve, 10000));

const checkExists = await document.get().then((doc) => doc.exists);
expect(checkExists).toBe(true);
}, 60000);

test("can check a document without any field values", async () => {
await db.collection(generateRandomId()).add({});
await search(user.uid, 1, db);
Expand Down
13 changes: 11 additions & 2 deletions delete-user-data/functions/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@
* limitations under the License.
*/

import { DocumentReference, FieldPath } from "firebase-admin/firestore";
import {
DocumentReference,
DocumentSnapshot,
FieldPath,
} from "firebase-admin/firestore";
import config from "./config";

export const getNestedFieldValue = (
snapshot: DocumentSnapshot,
field: string
) => snapshot.get(new FieldPath(...field.trim().split(".")));

export const getDatabaseUrl = (
selectedDatabaseInstance: string | undefined,
selectedDatabaseLocation: string | undefined
Expand All @@ -42,7 +51,7 @@ export const hasValidUserPath = async (

if (snapshot.exists) {
for (const field of config.searchFields.split(",")) {
const fieldValue = snapshot.get(new FieldPath(field));
const fieldValue = getNestedFieldValue(snapshot, field);

/** Return if a matching string includes the id */
if (typeof fieldValue === "string" && fieldValue.includes(uid)) {
Expand Down
17 changes: 10 additions & 7 deletions delete-user-data/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
*/

import * as admin from "firebase-admin";
import {
FieldPath,
DocumentReference,
getFirestore,
} from "firebase-admin/firestore";
import { DocumentReference, getFirestore } from "firebase-admin/firestore";
import * as functions from "firebase-functions";
import { getDatabaseUrl, hasValidUserPath } from "./helpers";
import {
getDatabaseUrl,
getNestedFieldValue,
hasValidUserPath,
} from "./helpers";
import chunk from "lodash.chunk";
import { getEventarc } from "firebase-admin/eventarc";

Expand Down Expand Up @@ -177,7 +177,10 @@ export const handleSearch = functions.pubsub
for (const snapshot of snapshots) {
if (snapshot.exists) {
for (const field of config.searchFields.split(",")) {
if (snapshot.get(new FieldPath(field)) === uid) {
if (
field.trim() &&
getNestedFieldValue(snapshot, field) === uid
) {
pathsToDelete.push(snapshot.ref.path);
continue;
}
Expand Down
Loading