Skip to content

Commit 7f81c35

Browse files
committed
feat: TODO의 카테고리를 변경하면 그에 대응되는 푸시 알림의 데이터도 수정되도록 구현
1 parent 10b5d13 commit 7f81c35

3 files changed

Lines changed: 117 additions & 1 deletion

File tree

Firebase/functions/src/fcm/notification.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const sendPushNotification = onTaskDispatched({
4242
logger.warn("notificationTask 문서 형식이 올바르지 않습니다.", { taskId });
4343
return;
4444
}
45-
const { userId, todoId, todoCategory, dueDateKey, title, body } = parsed;
45+
const { userId, todoId, dueDateKey, title, body } = parsed;
4646

4747
const settingsDocRef = admin.firestore().doc(`users/${userId}/userData/settings`);
4848
const todoDocRef = admin.firestore().doc(`users/${userId}/todoLists/${todoId}`);
@@ -56,6 +56,8 @@ export const sendPushNotification = onTaskDispatched({
5656

5757
const todoData = todoDoc.data();
5858
if (!todoDoc.exists || !todoData || todoData.isCompleted === true) { return; }
59+
const todoCategory = typeof todoData.category === "string" ? todoData.category.trim() : "";
60+
if (!todoCategory) { return; }
5961

6062
const timeZone = resolveTimeZone(settingsData);
6163

Firebase/functions/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ import {
3838
cleanupUnusedTodoNotificationRecords
3939
} from "./todo/cleanup";
4040

41+
import {
42+
syncTodoNotificationCategory
43+
} from "./todo/update";
44+
4145
import {
4246
requestMoveRemovedCategoryTodosToEtc,
4347
completeMoveRemovedCategoryTodosToEtc
@@ -101,6 +105,7 @@ export {
101105
removeTodoNotificationDocuments,
102106
removeCompletedTodoNotificationRecords,
103107
cleanupUnusedTodoNotificationRecords,
108+
syncTodoNotificationCategory,
104109
requestMoveRemovedCategoryTodosToEtc,
105110
completeMoveRemovedCategoryTodosToEtc,
106111
requestTodoDeletion,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { onDocumentUpdated } from "firebase-functions/v2/firestore";
2+
import * as admin from "firebase-admin";
3+
import * as logger from "firebase-functions/logger";
4+
import { normalizeError } from "../common/error";
5+
6+
const LOCATION = "asia-northeast3";
7+
const BATCH_SIZE = 200;
8+
9+
export const syncTodoNotificationCategory = onDocumentUpdated({
10+
document: "users/{userId}/todoLists/{todoId}",
11+
region: LOCATION
12+
},
13+
async (event) => {
14+
const beforeData = event.data?.before.data();
15+
const afterData = event.data?.after.data();
16+
const userId = event.params.userId;
17+
const todoId = event.params.todoId;
18+
19+
const beforeCategory = typeof beforeData?.category === "string" ? beforeData.category.trim() : "";
20+
const afterCategory = typeof afterData?.category === "string" ? afterData.category.trim() : "";
21+
22+
if (!beforeCategory || !afterCategory || beforeCategory == afterCategory) {
23+
return;
24+
}
25+
26+
try {
27+
await Promise.all([
28+
updateNotifications(userId, todoId, afterCategory),
29+
updateNotificationTasks(userId, todoId, afterCategory)
30+
]);
31+
} catch (error) {
32+
logger.error("todo 카테고리 변경 후 알림 데이터 동기화 실패", {
33+
userId,
34+
todoId,
35+
beforeCategory,
36+
afterCategory,
37+
error: normalizeError(error)
38+
});
39+
throw error;
40+
}
41+
}
42+
);
43+
44+
async function updateNotifications(
45+
userId: string,
46+
todoId: string,
47+
todoCategory: string
48+
): Promise<void> {
49+
let lastDocument:
50+
FirebaseFirestore.QueryDocumentSnapshot<FirebaseFirestore.DocumentData> | undefined;
51+
52+
while (true) {
53+
let query = admin.firestore()
54+
.collection(`users/${userId}/notifications`)
55+
.where("todoId", "==", todoId)
56+
.orderBy(admin.firestore.FieldPath.documentId())
57+
.limit(BATCH_SIZE);
58+
59+
if (lastDocument) {
60+
query = query.startAfter(lastDocument);
61+
}
62+
63+
const snapshot = await query.get();
64+
if (snapshot.empty) { return; }
65+
66+
const batch = admin.firestore().batch();
67+
snapshot.docs.forEach((document) => {
68+
batch.update(document.ref, { todoCategory });
69+
});
70+
await batch.commit();
71+
72+
if (snapshot.size < BATCH_SIZE) { return; }
73+
lastDocument = snapshot.docs[snapshot.docs.length - 1];
74+
}
75+
}
76+
77+
async function updateNotificationTasks(
78+
userId: string,
79+
todoId: string,
80+
todoCategory: string
81+
): Promise<void> {
82+
let lastDocument:
83+
FirebaseFirestore.QueryDocumentSnapshot<FirebaseFirestore.DocumentData> | undefined;
84+
85+
while (true) {
86+
let query = admin.firestore()
87+
.collection("notificationTasks")
88+
.where("userId", "==", userId)
89+
.where("todoId", "==", todoId)
90+
.orderBy(admin.firestore.FieldPath.documentId())
91+
.limit(BATCH_SIZE);
92+
93+
if (lastDocument) {
94+
query = query.startAfter(lastDocument);
95+
}
96+
97+
const snapshot = await query.get();
98+
if (snapshot.empty) { return; }
99+
100+
const batch = admin.firestore().batch();
101+
snapshot.docs.forEach((document) => {
102+
batch.update(document.ref, { todoCategory });
103+
});
104+
await batch.commit();
105+
106+
if (snapshot.size < BATCH_SIZE) { return; }
107+
lastDocument = snapshot.docs[snapshot.docs.length - 1];
108+
}
109+
}

0 commit comments

Comments
 (0)