Vue로 PWA 개발 - 그랜파 개발자
마이로그를 쓰면 구독자에게 알림을 전송하는 기능을 구현합니다. 잎에서 구현한 FCM 푸시 메시지 전송 기능을 그대로 두고 새로운 함수로 기능을 구현하고자 합니다.
Cloud Firestore 함수 트리거의 onDocumentCreated 이벤트는 문서를 처음으로 기록할 때 트리거됩니다. 이 이벤트를 받아 구독자에게 알림을 전송하는 기능을 구현합니다.
1. 구독자 알림 전송
2. funcstions/index.js
// funcstions/index.js
const { onRequest } = require("firebase-functions/v2/https");
const { onDocumentCreated } = require('firebase-functions/v2/firestore');
const logger = require("firebase-functions/logger");
//const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({ origin: true }); // Allow all origins
// Initialize Firebase Admin
admin.initializeApp();
// Reference to Firestore
const db = admin.firestore();
// Cloud Function to send push notifications
exports.sendPushNotification = onRequest(async (req, res) => {
cors(req, res, async () => {
try {
// Retrieve the FCM token(s) from Firestore or request body
const {userId, title, body } = req.body; //.userId;
const tokenSnapshot = await admin.firestore().collection('fcmTokens').doc(userId).get();
if (!tokenSnapshot.exists) {
return res.status(404).send('User not found');
}
// 한 회원이 여러 토큰을 가진다. PC, 모바일 등
const tokens = tokenSnapshot.data().tokens;
console.log('tokens: ', tokens);
// Token을 배열에 넣는다.
const fcmTokens = [];
tokens.forEach((token) => {
// doc.data() is never undefined for query doc snapshots
fcmTokens.push(token.token);
});
try {
const response = await admin.messaging().sendEachForMulticast({
tokens: fcmTokens,
notification: {
title: title,
body: body,
}
});
// Check the results of the notifications
response.responses.forEach((response, idx) => {
if (response.success) {
console.log(`Message sent successfully to token: ${fcmTokens[idx]}`);
} else {
console.error(`Failed to send message to token: ${fcmTokens[idx]}`, response.error);
}
});
return res.status(200).send('Notification sent successfully');
} catch (error) {
console.error('Error sending multicast notifications:', error);
}
} catch (error) {
console.error('Error sending notification:', error);
return res.status(500).send('Failed to send notification');
}
})
});
// 마이로그를 쓰면 구독자에게 알림을 전송한다.
exports.sendMylogNotification = onDocumentCreated('/mylogs/{mylogId}', async (event) => {
const snapshot = event.data;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// access a particular field as you would any JS property
const authorId = data.userId;
const title = data.title;
const content = data.content;
try {
// userId는 저자이다. 저자의 독자들을 가져와야 한다.
// subscriptions 컬렉션의 구조: userId: userId, authorId: authorId, createdAt: new Date(),
const readersSnapshot = await db.collection('subscriptions')
.where('authorId', '==', authorId) // Query for posts where 'authorId' matches
.get();
const readerIds = [];
readersSnapshot.forEach((doc) => {
readerIds.push(doc.data().userId);
});
// readerIds 에 userId가 있는 모든 독자에게 알림 전송
for (const userId of readerIds) {
// 각 회원의 토큰을 가져온다.
const tokenSnapshot = await admin.firestore().collection('fcmTokens').doc(userId).get();
// 토근이 있으면 알림을 전송한다.
if (tokenSnapshot.exists) {
// 한 회원이 여러 토큰을 가진다. PC, 모바일 등
const tokens = tokenSnapshot.data().tokens;
console.log('tokens: ', tokens);
// Token을 배열에 넣는다.
const fcmTokens = [];
tokens.forEach((token) => {
// doc.data() is never undefined for query doc snapshots
fcmTokens.push(token.token);
});
try {
const response = await admin.messaging().sendEachForMulticast({
tokens: fcmTokens,
notification: {
title: title,
body: content,
}
});
// Check the results of the notifications
response.responses.forEach((response, idx) => {
if (response.success) {
console.log(`Message sent successfully to token: ${fcmTokens[idx]}`);
} else {
console.error(`Failed to send message to token: ${fcmTokens[idx]}`, response.error);
}
});
//return res.status(200).send('Notification sent successfully');
} catch (error) {
console.error('Error sending multicast notifications:', error);
}
}
}
} catch (error) {
console.error('Error getting readers:', error);
//res.status(500).send('Error getting readers');
}
});
3. Cloud Firestore 함수 트리거
마이로그가 저장될 때 이벤트를 받아 마이로그의 저자로 구독자를 찾아 구독자의 토큰을사용하여 FCM 알림을 전송합니다.
onDocumentCreated
// funcstions/index.js
const { onRequest } = require("firebase-functions/v2/https");
const { onDocumentCreated } = require('firebase-functions/v2/firestore');
const logger = require("firebase-functions/logger");
//const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({ origin: true }); // Allow all origins
// Initialize Firebase Admin
admin.initializeApp();
// Reference to Firestore
const db = admin.firestore();
. . .
// 마이로그를 쓰면 구독자에게 알림을 전송한다.
exports.sendMylogNotification = onDocumentCreated('/mylogs/{mylogId}', async (event) => {
const snapshot = event.data;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// access a particular field as you would any JS property
const authorId = data.userId;
const title = data.title;
const content = data.content;
try {
// userId는 저자이다. 저자의 독자들을 가져와야 한다.
// subscriptions 컬렉션의 구조: userId: userId, authorId: authorId, createdAt: new Date(),
const readersSnapshot = await db.collection('subscriptions')
.where('authorId', '==', authorId) // Query for posts where 'authorId' matches
.get();
const readerIds = [];
readersSnapshot.forEach((doc) => {
readerIds.push(doc.data().userId);
});
// readerIds 에 userId가 있는 모든 독자에게 알림 전송
for (const userId of readerIds) {
// 각 회원의 토큰을 가져온다.
const tokenSnapshot = await admin.firestore().collection('fcmTokens').doc(userId).get();
// 토근이 있으면 알림을 전송한다.
if (tokenSnapshot.exists) {
// 한 회원이 여러 토큰을 가진다. PC, 모바일 등
const tokens = tokenSnapshot.data().tokens;
console.log('tokens: ', tokens);
// Token을 배열에 넣는다.
const fcmTokens = [];
tokens.forEach((token) => {
// doc.data() is never undefined for query doc snapshots
fcmTokens.push(token.token);
});
try {
const response = await admin.messaging().sendEachForMulticast({
tokens: fcmTokens,
notification: {
title: title,
body: content,
}
});
// Check the results of the notifications
response.responses.forEach((response, idx) => {
if (response.success) {
console.log(`Message sent successfully to token: ${fcmTokens[idx]}`);
} else {
console.error(`Failed to send message to token: ${fcmTokens[idx]}`, response.error);
}
});
//return res.status(200).send('Notification sent successfully');
} catch (error) {
console.error('Error sending multicast notifications:', error);
}
}
}
} catch (error) {
console.error('Error getting readers:', error);
//res.status(500).send('Error getting readers');
}
});
'Vue로 PWA 개발' 카테고리의 다른 글
59. myLog 날짜별 조회수 (1) | 2024.11.03 |
---|---|
58. mylog 통계 (0) | 2024.11.03 |
56. mylog Firebase Cloud Functions에서 Firestore query 사용 (0) | 2024.11.02 |
55. mylog Firebase Cloud Functions에서 Firestore 사용 (0) | 2024.11.02 |
54. mylog Firebase Cloud Functions에서의 함수들 (0) | 2024.11.02 |