feat: fixes and formatter
This commit is contained in:
+239
-284
@@ -1,100 +1,88 @@
|
||||
const {
|
||||
onDocumentCreated,
|
||||
onDocumentWritten,
|
||||
} = require("firebase-functions/v2/firestore");
|
||||
const { FieldValue } = require("firebase-admin/firestore");
|
||||
const { refList, ALERT_TYPE } = require("../index");
|
||||
const { Expo } = require("expo-server-sdk");
|
||||
const { Resend } = require("resend");
|
||||
const { basicTemplate } = require("../helpers/email");
|
||||
const { RESEND_API_KEY } = require("../config/keys");
|
||||
const { onDocumentCreated, onDocumentWritten } = require('firebase-functions/v2/firestore')
|
||||
const { FieldValue } = require('firebase-admin/firestore')
|
||||
const { refList, ALERT_TYPE } = require('../index')
|
||||
const { Expo } = require('expo-server-sdk')
|
||||
const { Resend } = require('resend')
|
||||
const { basicTemplate } = require('../helpers/email')
|
||||
const { RESEND_API_KEY } = require('../config/keys')
|
||||
|
||||
const resendInstance = RESEND_API_KEY ? new Resend(RESEND_API_KEY) : null;
|
||||
const resendInstance = RESEND_API_KEY ? new Resend(RESEND_API_KEY) : null
|
||||
|
||||
// Initialisation de Expo SDK
|
||||
let expo = new Expo();
|
||||
const EMAIL_FROM = "MusicLand <musicland@musicland.ai>";
|
||||
const DEFAULT_EMAIL_TITLE = "MusicLand";
|
||||
let expo = new Expo()
|
||||
const EMAIL_FROM = 'MusicLand <musicland@musicland.ai>'
|
||||
const DEFAULT_EMAIL_TITLE = 'MusicLand'
|
||||
|
||||
function getCollectionRef(collectionName = "") {
|
||||
const ref = refList?.[collectionName];
|
||||
function getCollectionRef(collectionName = '') {
|
||||
const ref = refList?.[collectionName]
|
||||
if (!ref) {
|
||||
throw new Error(`Unknown collection "${collectionName}"`);
|
||||
throw new Error(`Unknown collection "${collectionName}"`)
|
||||
}
|
||||
return ref;
|
||||
return ref
|
||||
}
|
||||
|
||||
function cleanString(value) {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : null;
|
||||
return typeof value === 'string' && value.trim() ? value.trim() : null
|
||||
}
|
||||
|
||||
function buildNotificationEmailPayload({
|
||||
title = "",
|
||||
message = "",
|
||||
template = {},
|
||||
} = {}) {
|
||||
const fallbackTitle = cleanString(title) || DEFAULT_EMAIL_TITLE;
|
||||
const fallbackContent = cleanString(message) || "";
|
||||
const overrides = template && typeof template === "object" ? template : {};
|
||||
function buildNotificationEmailPayload({ title = '', message = '', template = {} } = {}) {
|
||||
const fallbackTitle = cleanString(title) || DEFAULT_EMAIL_TITLE
|
||||
const fallbackContent = cleanString(message) || ''
|
||||
const overrides = template && typeof template === 'object' ? template : {}
|
||||
|
||||
const subject = cleanString(overrides.subject) || fallbackTitle;
|
||||
const emailTitle = cleanString(overrides.title) || fallbackTitle;
|
||||
const content = cleanString(overrides.content) || fallbackContent;
|
||||
const subject = cleanString(overrides.subject) || fallbackTitle
|
||||
const emailTitle = cleanString(overrides.title) || fallbackTitle
|
||||
const content = cleanString(overrides.content) || fallbackContent
|
||||
|
||||
let button = null;
|
||||
if (overrides.button && typeof overrides.button === "object") {
|
||||
const buttonUrl =
|
||||
cleanString(overrides.button.url) || cleanString(overrides.button.href);
|
||||
let button = null
|
||||
if (overrides.button && typeof overrides.button === 'object') {
|
||||
const buttonUrl = cleanString(overrides.button.url) || cleanString(overrides.button.href)
|
||||
if (buttonUrl) {
|
||||
button = {
|
||||
url: buttonUrl,
|
||||
label:
|
||||
cleanString(overrides.button.label) ||
|
||||
cleanString(overrides.button.text) ||
|
||||
undefined,
|
||||
};
|
||||
cleanString(overrides.button.label) || cleanString(overrides.button.text) || undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const templatePayload = { title: emailTitle, content };
|
||||
const templatePayload = { title: emailTitle, content }
|
||||
if (button) {
|
||||
templatePayload.button = button;
|
||||
templatePayload.button = button
|
||||
}
|
||||
|
||||
return {
|
||||
subject,
|
||||
html: basicTemplate(templatePayload),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
exports.sendNotificationWhenDocIsCreated = onDocumentCreated(
|
||||
{ region: "europe-west1", document: "notifications/{notificationId}" },
|
||||
{ region: 'europe-west1', document: 'notifications/{notificationId}' },
|
||||
async (event) => {
|
||||
try {
|
||||
const {
|
||||
receiver = null,
|
||||
title = "MusicLand",
|
||||
receiverCollection = "users",
|
||||
message = "",
|
||||
title = 'MusicLand',
|
||||
receiverCollection = 'users',
|
||||
message = '',
|
||||
data: notifData = {},
|
||||
mailOnly = false,
|
||||
} = event.data.data();
|
||||
} = event.data.data()
|
||||
|
||||
if (!receiver || !message) {
|
||||
throw new Error("Receiver and message are required");
|
||||
throw new Error('Receiver and message are required')
|
||||
}
|
||||
|
||||
const receiverSnap = await getCollectionRef(receiverCollection)
|
||||
.doc(receiver)
|
||||
.get();
|
||||
const receiverData = receiverSnap.exists ? receiverSnap.data() : {};
|
||||
const receiverSnap = await getCollectionRef(receiverCollection).doc(receiver).get()
|
||||
const receiverData = receiverSnap.exists ? receiverSnap.data() : {}
|
||||
|
||||
const {
|
||||
pushToken = null,
|
||||
pushTokens = [],
|
||||
email: receiverEmail = "",
|
||||
email: receiverEmail = '',
|
||||
emailNotifications = false,
|
||||
} = receiverData;
|
||||
} = receiverData
|
||||
|
||||
if (!mailOnly) {
|
||||
try {
|
||||
@@ -102,129 +90,124 @@ exports.sendNotificationWhenDocIsCreated = onDocumentCreated(
|
||||
[]
|
||||
.concat(Array.isArray(pushTokens) ? pushTokens : [])
|
||||
.concat(pushToken ? [pushToken] : [])
|
||||
.filter(Boolean),
|
||||
);
|
||||
const tokens = Array.from(tokensSet);
|
||||
.filter(Boolean)
|
||||
)
|
||||
const tokens = Array.from(tokensSet)
|
||||
|
||||
if (!tokens?.length) {
|
||||
await sendExpoNotification({
|
||||
tokens,
|
||||
receiverId: receiver,
|
||||
receiverCollection,
|
||||
title: title || "MusicLand",
|
||||
title: title || 'MusicLand',
|
||||
message: message,
|
||||
data: notifData || {},
|
||||
});
|
||||
})
|
||||
} else {
|
||||
console.log("User push token not found");
|
||||
console.log('User push token not found')
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error sending notif:", e);
|
||||
console.log('Error sending notif:', e)
|
||||
}
|
||||
}
|
||||
|
||||
if ((emailNotifications || mailOnly) && !!receiverEmail) {
|
||||
if (!resendInstance) {
|
||||
console.warn(
|
||||
"Resend client not configured; unable to send notification email.",
|
||||
);
|
||||
console.warn('Resend client not configured; unable to send notification email.')
|
||||
} else {
|
||||
try {
|
||||
const { subject, html } = buildNotificationEmailPayload({
|
||||
title,
|
||||
message,
|
||||
template: notifData?.email,
|
||||
});
|
||||
})
|
||||
await resendInstance.emails.send({
|
||||
from: EMAIL_FROM,
|
||||
to: [receiverEmail],
|
||||
subject,
|
||||
html,
|
||||
});
|
||||
})
|
||||
} catch (e) {
|
||||
console.log("Error sending email:", e);
|
||||
console.log('Error sending email:', e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
`[sendNotificationWhenDocIsCreated] Email not sent (${receiverEmail ? "user preference" : "missing email"}) for user ${receiver} and type ${notifData?.type || "UNKNOWN"}`,
|
||||
);
|
||||
`[sendNotificationWhenDocIsCreated] Email not sent (${receiverEmail ? 'user preference' : 'missing email'}) for user ${receiver} and type ${notifData?.type || 'UNKNOWN'}`
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return e;
|
||||
console.log(e)
|
||||
return e
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
// Fonction pour envoyer la notification via Expo SDK
|
||||
async function sendExpoNotification({
|
||||
tokens = [],
|
||||
title = "",
|
||||
message = "",
|
||||
title = '',
|
||||
message = '',
|
||||
data = {},
|
||||
receiverId = null,
|
||||
receiverCollection = "users",
|
||||
receiverCollection = 'users',
|
||||
}) {
|
||||
try {
|
||||
const candidateTokens = Array.isArray(tokens) ? tokens : [tokens];
|
||||
const validTokens = [];
|
||||
const invalidTokens = [];
|
||||
const candidateTokens = Array.isArray(tokens) ? tokens : [tokens]
|
||||
const validTokens = []
|
||||
const invalidTokens = []
|
||||
|
||||
candidateTokens.forEach((token) => {
|
||||
if (Expo.isExpoPushToken(token)) {
|
||||
validTokens.push(token);
|
||||
validTokens.push(token)
|
||||
} else if (token) {
|
||||
invalidTokens.push(token);
|
||||
invalidTokens.push(token)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
if (invalidTokens.length && receiverId) {
|
||||
await removeInvalidTokens({
|
||||
tokens: invalidTokens,
|
||||
receiverId,
|
||||
receiverCollection,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (!validTokens.length) {
|
||||
console.warn("No valid Expo push tokens to send notification");
|
||||
return { sent: false };
|
||||
console.warn('No valid Expo push tokens to send notification')
|
||||
return { sent: false }
|
||||
}
|
||||
|
||||
const messages = validTokens.map((token) => ({
|
||||
to: token,
|
||||
sound: "default",
|
||||
sound: 'default',
|
||||
title: title,
|
||||
body: message,
|
||||
data: data || {},
|
||||
priority: "high",
|
||||
priority: 'high',
|
||||
badge: 1,
|
||||
channelId: "default",
|
||||
}));
|
||||
channelId: 'default',
|
||||
}))
|
||||
|
||||
const chunks = expo.chunkPushNotifications(messages);
|
||||
const receipts = [];
|
||||
const tokensToPrune = new Set();
|
||||
const chunks = expo.chunkPushNotifications(messages)
|
||||
const receipts = []
|
||||
const tokensToPrune = new Set()
|
||||
|
||||
for (const chunk of chunks) {
|
||||
const chunkReceipts = await expo.sendPushNotificationsAsync(chunk);
|
||||
const chunkReceipts = await expo.sendPushNotificationsAsync(chunk)
|
||||
chunkReceipts.forEach((receipt, index) => {
|
||||
if (receipt?.status === "error") {
|
||||
const errorCode = receipt?.details?.error || receipt?.details?.code;
|
||||
console.log("Error sending notification:", receipt);
|
||||
if (
|
||||
errorCode === "DeviceNotRegistered" ||
|
||||
errorCode === "PushTokenNotRegistered"
|
||||
) {
|
||||
const token = chunk[index]?.to;
|
||||
if (receipt?.status === 'error') {
|
||||
const errorCode = receipt?.details?.error || receipt?.details?.code
|
||||
console.log('Error sending notification:', receipt)
|
||||
if (errorCode === 'DeviceNotRegistered' || errorCode === 'PushTokenNotRegistered') {
|
||||
const token = chunk[index]?.to
|
||||
if (token) {
|
||||
tokensToPrune.add(token);
|
||||
tokensToPrune.add(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
receipts.push(...chunkReceipts);
|
||||
})
|
||||
receipts.push(...chunkReceipts)
|
||||
}
|
||||
|
||||
if (tokensToPrune.size && receiverId) {
|
||||
@@ -232,68 +215,64 @@ async function sendExpoNotification({
|
||||
tokens: Array.from(tokensToPrune),
|
||||
receiverId,
|
||||
receiverCollection,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
console.log("Sent push notifications:", receipts);
|
||||
console.log('Sent push notifications:', receipts)
|
||||
|
||||
return { sent: true };
|
||||
return { sent: true }
|
||||
} catch (e) {
|
||||
console.log("Error sending notification:", e);
|
||||
throw e;
|
||||
console.log('Error sending notification:', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async function removeInvalidTokens({
|
||||
tokens = [],
|
||||
receiverId,
|
||||
receiverCollection,
|
||||
}) {
|
||||
async function removeInvalidTokens({ tokens = [], receiverId, receiverCollection }) {
|
||||
try {
|
||||
if (!receiverId || !tokens.length) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const uniqueTokens = Array.from(new Set(tokens.filter(Boolean)));
|
||||
const uniqueTokens = Array.from(new Set(tokens.filter(Boolean)))
|
||||
if (!uniqueTokens.length) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const docRef = getCollectionRef(receiverCollection).doc(receiverId);
|
||||
const userSnap = await docRef.get();
|
||||
const userData = userSnap?.data() || {};
|
||||
const docRef = getCollectionRef(receiverCollection).doc(receiverId)
|
||||
const userSnap = await docRef.get()
|
||||
const userData = userSnap?.data() || {}
|
||||
|
||||
const updates = {
|
||||
pushTokens: FieldValue.arrayRemove(...uniqueTokens),
|
||||
};
|
||||
|
||||
if (uniqueTokens.includes(userData?.pushToken)) {
|
||||
updates.pushToken = FieldValue.delete();
|
||||
}
|
||||
|
||||
await docRef.set(updates, { merge: true });
|
||||
if (uniqueTokens.includes(userData?.pushToken)) {
|
||||
updates.pushToken = FieldValue.delete()
|
||||
}
|
||||
|
||||
await docRef.set(updates, { merge: true })
|
||||
console.log(
|
||||
"Pruned invalid push tokens",
|
||||
JSON.stringify({ receiverId, tokens: uniqueTokens }, null, 2),
|
||||
);
|
||||
'Pruned invalid push tokens',
|
||||
JSON.stringify({ receiverId, tokens: uniqueTokens }, null, 2)
|
||||
)
|
||||
} catch (error) {
|
||||
console.log("Failed to prune invalid push tokens:", error);
|
||||
console.log('Failed to prune invalid push tokens:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction pour ajouter une notification à la base de données
|
||||
const sendNotification = async ({
|
||||
sender = "SYSTEM",
|
||||
sender = 'SYSTEM',
|
||||
receiver = null,
|
||||
receiverCollection = "users",
|
||||
title = "",
|
||||
receiverCollection = 'users',
|
||||
title = '',
|
||||
message = null,
|
||||
mailOnly = false,
|
||||
data = {},
|
||||
}) => {
|
||||
try {
|
||||
if (!receiver || !message) {
|
||||
throw new Error("Receiver and message are required");
|
||||
throw new Error('Receiver and message are required')
|
||||
}
|
||||
const payload = {
|
||||
sender,
|
||||
@@ -306,81 +285,78 @@ const sendNotification = async ({
|
||||
readAt: null,
|
||||
mailOnly,
|
||||
data,
|
||||
};
|
||||
const { id } = await refList.notifications.add(payload);
|
||||
}
|
||||
const { id } = await refList.notifications.add(payload)
|
||||
console.log(
|
||||
"[sendNotification] Notification created",
|
||||
JSON.stringify({ id, receiver, receiverCollection }, null, 2),
|
||||
);
|
||||
'[sendNotification] Notification created',
|
||||
JSON.stringify({ id, receiver, receiverCollection }, null, 2)
|
||||
)
|
||||
|
||||
return id;
|
||||
return id
|
||||
} catch (e) {
|
||||
console.log("[sendNotification] Error creating notification:", e);
|
||||
console.log('[sendNotification] Error creating notification:', e)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.sendNotification = sendNotification;
|
||||
exports.sendNotification = sendNotification
|
||||
|
||||
exports.createProjectCommentNotification = onDocumentCreated(
|
||||
{
|
||||
region: "europe-west1",
|
||||
document: "projects/{projectId}/comments/{commentId}",
|
||||
region: 'europe-west1',
|
||||
document: 'projects/{projectId}/comments/{commentId}',
|
||||
},
|
||||
async (event) => {
|
||||
try {
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Trigger received",
|
||||
JSON.stringify(event.params || {}, null, 2),
|
||||
);
|
||||
const { data: snap } = event;
|
||||
const { projectId, commentId } = event.params || {};
|
||||
const comment = snap?.data();
|
||||
'[createProjectCommentNotification] Trigger received',
|
||||
JSON.stringify(event.params || {}, null, 2)
|
||||
)
|
||||
const { data: snap } = event
|
||||
const { projectId, commentId } = event.params || {}
|
||||
const comment = snap?.data()
|
||||
|
||||
if (!projectId || !comment) {
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Missing project/comment data",
|
||||
{ hasProjectId: !!projectId, hasComment: !!comment },
|
||||
);
|
||||
return null;
|
||||
console.log('[createProjectCommentNotification] Missing project/comment data', {
|
||||
hasProjectId: !!projectId,
|
||||
hasComment: !!comment,
|
||||
})
|
||||
return null
|
||||
}
|
||||
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Comment payload",
|
||||
JSON.stringify(comment, null, 2),
|
||||
);
|
||||
'[createProjectCommentNotification] Comment payload',
|
||||
JSON.stringify(comment, null, 2)
|
||||
)
|
||||
|
||||
const projectSnap = await refList.projects.doc(projectId).get();
|
||||
const projectSnap = await refList.projects.doc(projectId).get()
|
||||
if (!projectSnap.exists) {
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Project not found",
|
||||
projectId,
|
||||
);
|
||||
return null;
|
||||
console.log('[createProjectCommentNotification] Project not found', projectId)
|
||||
return null
|
||||
}
|
||||
|
||||
const project = projectSnap.data() || {};
|
||||
const receiver = project.userId || null;
|
||||
const project = projectSnap.data() || {}
|
||||
const receiver = project.userId || null
|
||||
|
||||
if (!receiver || receiver === comment.userId) {
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Invalid receiver",
|
||||
JSON.stringify({ receiver, commentUserId: comment.userId }),
|
||||
);
|
||||
return null;
|
||||
'[createProjectCommentNotification] Invalid receiver',
|
||||
JSON.stringify({ receiver, commentUserId: comment.userId })
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const commenterName =
|
||||
typeof comment?.userName === "string" && comment.userName.trim()
|
||||
typeof comment?.userName === 'string' && comment.userName.trim()
|
||||
? comment.userName.trim()
|
||||
: "Un utilisateur";
|
||||
: 'Un utilisateur'
|
||||
const projectTitle =
|
||||
typeof project.title === "string" && project.title.trim()
|
||||
typeof project.title === 'string' && project.title.trim()
|
||||
? project.title.trim()
|
||||
: "ton projet";
|
||||
const message = `${commenterName} a commenté ton projet "${projectTitle}"`;
|
||||
: 'ton projet'
|
||||
const message = `${commenterName} a commenté ton projet "${projectTitle}"`
|
||||
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Creating notification",
|
||||
'[createProjectCommentNotification] Creating notification',
|
||||
JSON.stringify(
|
||||
{
|
||||
receiver,
|
||||
@@ -389,15 +365,15 @@ exports.createProjectCommentNotification = onDocumentCreated(
|
||||
projectId,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
2
|
||||
)
|
||||
)
|
||||
|
||||
await sendNotification({
|
||||
sender: comment.userId || "SYSTEM",
|
||||
sender: comment.userId || 'SYSTEM',
|
||||
receiver,
|
||||
receiverCollection: "users",
|
||||
title: "Nouveau commentaire",
|
||||
receiverCollection: 'users',
|
||||
title: 'Nouveau commentaire',
|
||||
message,
|
||||
data: {
|
||||
type: ALERT_TYPE?.NEW_COMMENT,
|
||||
@@ -405,109 +381,94 @@ exports.createProjectCommentNotification = onDocumentCreated(
|
||||
commentId,
|
||||
commenterId: comment.userId || null,
|
||||
commenterName: commenterName,
|
||||
commenterProfilePicture: comment?.profilePicture || "",
|
||||
text:
|
||||
typeof comment?.text === "string" && comment.text.trim()
|
||||
? comment.text.trim()
|
||||
: "",
|
||||
commenterProfilePicture: comment?.profilePicture || '',
|
||||
text: typeof comment?.text === 'string' && comment.text.trim() ? comment.text.trim() : '',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
console.log(
|
||||
"[createProjectCommentNotification] Notification creation complete",
|
||||
);
|
||||
console.log('[createProjectCommentNotification] Notification creation complete')
|
||||
|
||||
return null;
|
||||
return null
|
||||
} catch (error) {
|
||||
console.log("createProjectCommentNotification error:", error);
|
||||
return error;
|
||||
console.log('createProjectCommentNotification error:', error)
|
||||
return error
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
exports.createProjectLikeNotification = onDocumentWritten(
|
||||
{
|
||||
region: "europe-west1",
|
||||
document: "projects/{projectId}",
|
||||
region: 'europe-west1',
|
||||
document: 'projects/{projectId}',
|
||||
},
|
||||
async (event) => {
|
||||
try {
|
||||
const { projectId } = event.params || {};
|
||||
const before = event?.data?.before?.data() || {};
|
||||
const after = event?.data?.after?.data() || {};
|
||||
const { projectId } = event.params || {}
|
||||
const before = event?.data?.before?.data() || {}
|
||||
const after = event?.data?.after?.data() || {}
|
||||
|
||||
if (!projectId || !after) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const ownerId = after.userId || null;
|
||||
const ownerId = after.userId || null
|
||||
if (!ownerId) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const beforeSongLikes = Array.isArray(before?.likes?.song)
|
||||
? before.likes.song
|
||||
: [];
|
||||
const afterSongLikes = Array.isArray(after?.likes?.song)
|
||||
? after.likes.song
|
||||
: [];
|
||||
const beforeSongLikes = Array.isArray(before?.likes?.song) ? before.likes.song : []
|
||||
const afterSongLikes = Array.isArray(after?.likes?.song) ? after.likes.song : []
|
||||
const beforePlaybackLikes = Array.isArray(before?.likes?.playback)
|
||||
? before.likes.playback
|
||||
: [];
|
||||
const afterPlaybackLikes = Array.isArray(after?.likes?.playback)
|
||||
? after.likes.playback
|
||||
: [];
|
||||
: []
|
||||
const afterPlaybackLikes = Array.isArray(after?.likes?.playback) ? after.likes.playback : []
|
||||
|
||||
const beforeSongSet = new Set(beforeSongLikes);
|
||||
const beforePlaybackSet = new Set(beforePlaybackLikes);
|
||||
const beforeSongSet = new Set(beforeSongLikes)
|
||||
const beforePlaybackSet = new Set(beforePlaybackLikes)
|
||||
|
||||
const newSongLikers = afterSongLikes.filter(
|
||||
(uid) => uid && !beforeSongSet.has(uid),
|
||||
);
|
||||
const newSongLikers = afterSongLikes.filter((uid) => uid && !beforeSongSet.has(uid))
|
||||
const newPlaybackLikers = afterPlaybackLikes.filter(
|
||||
(uid) => uid && !beforePlaybackSet.has(uid),
|
||||
);
|
||||
(uid) => uid && !beforePlaybackSet.has(uid)
|
||||
)
|
||||
|
||||
const newLikers = [];
|
||||
const newLikers = []
|
||||
|
||||
newSongLikers.forEach((uid) => {
|
||||
newLikers.push({ likerId: uid, likeType: "song" });
|
||||
});
|
||||
newLikers.push({ likerId: uid, likeType: 'song' })
|
||||
})
|
||||
newPlaybackLikers.forEach((uid) => {
|
||||
newLikers.push({ likerId: uid, likeType: "playback" });
|
||||
});
|
||||
newLikers.push({ likerId: uid, likeType: 'playback' })
|
||||
})
|
||||
|
||||
if (!newLikers.length) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const projectTitle =
|
||||
typeof after.title === "string" && after.title.trim()
|
||||
? after.title.trim()
|
||||
: "ton projet";
|
||||
typeof after.title === 'string' && after.title.trim() ? after.title.trim() : 'ton projet'
|
||||
|
||||
await Promise.all(
|
||||
newLikers.map(async ({ likerId, likeType }) => {
|
||||
if (!likerId || likerId === ownerId) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const likerSnap = await refList.users.doc(likerId).get();
|
||||
const liker = likerSnap?.data() || {};
|
||||
const likerSnap = await refList.users.doc(likerId).get()
|
||||
const liker = likerSnap?.data() || {}
|
||||
const likerName =
|
||||
typeof liker?.userName === "string" && liker.userName.trim()
|
||||
typeof liker?.userName === 'string' && liker.userName.trim()
|
||||
? liker.userName.trim()
|
||||
: "Un utilisateur";
|
||||
: 'Un utilisateur'
|
||||
|
||||
const isPlaybackLike = likeType === "playback";
|
||||
const assetLabel = isPlaybackLike ? "ton playback" : "ta musique";
|
||||
const message = `${likerName} a aimé ${assetLabel} "${projectTitle}"`;
|
||||
const isPlaybackLike = likeType === 'playback'
|
||||
const assetLabel = isPlaybackLike ? 'ton playback' : 'ta musique'
|
||||
const message = `${likerName} a aimé ${assetLabel} "${projectTitle}"`
|
||||
|
||||
await sendNotification({
|
||||
sender: likerId,
|
||||
receiver: ownerId,
|
||||
receiverCollection: "users",
|
||||
title: "Nouveau like",
|
||||
receiverCollection: 'users',
|
||||
title: 'Nouveau like',
|
||||
message,
|
||||
data: {
|
||||
type: ALERT_TYPE?.NEW_LIKE,
|
||||
@@ -516,92 +477,86 @@ exports.createProjectLikeNotification = onDocumentWritten(
|
||||
likerName,
|
||||
likeType,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
return null;
|
||||
}),
|
||||
);
|
||||
return null
|
||||
})
|
||||
)
|
||||
|
||||
return null;
|
||||
return null
|
||||
} catch (error) {
|
||||
console.log("[createProjectLikeNotification] error:", error);
|
||||
return error;
|
||||
console.log('[createProjectLikeNotification] error:', error)
|
||||
return error
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
exports.createNewFollowerNotification = onDocumentWritten(
|
||||
{
|
||||
region: "europe-west1",
|
||||
document: "users/{userId}",
|
||||
region: 'europe-west1',
|
||||
document: 'users/{userId}',
|
||||
},
|
||||
async (event) => {
|
||||
try {
|
||||
const { userId } = event.params || {};
|
||||
const before = event?.data?.before?.data() || {};
|
||||
const after = event?.data?.after?.data() || {};
|
||||
const { userId } = event.params || {}
|
||||
const before = event?.data?.before?.data() || {}
|
||||
const after = event?.data?.after?.data() || {}
|
||||
|
||||
if (!userId || !after) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const beforeFollowers = Array.isArray(before?.followedBy)
|
||||
? before.followedBy
|
||||
: [];
|
||||
const afterFollowers = Array.isArray(after?.followedBy)
|
||||
? after.followedBy
|
||||
: [];
|
||||
const beforeFollowers = Array.isArray(before?.followedBy) ? before.followedBy : []
|
||||
const afterFollowers = Array.isArray(after?.followedBy) ? after.followedBy : []
|
||||
|
||||
if (afterFollowers.length <= beforeFollowers.length) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const previousSet = new Set(beforeFollowers);
|
||||
const newFollowers = afterFollowers.filter(
|
||||
(uid) => !previousSet.has(uid),
|
||||
);
|
||||
const previousSet = new Set(beforeFollowers)
|
||||
const newFollowers = afterFollowers.filter((uid) => !previousSet.has(uid))
|
||||
|
||||
if (!newFollowers.length) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
newFollowers.map(async (followerId) => {
|
||||
if (!followerId || followerId === userId) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const followerSnap = await refList.users.doc(followerId).get();
|
||||
const follower = followerSnap?.data() || {};
|
||||
const followerSnap = await refList.users.doc(followerId).get()
|
||||
const follower = followerSnap?.data() || {}
|
||||
const followerName =
|
||||
typeof follower?.userName === "string" && follower.userName.trim()
|
||||
typeof follower?.userName === 'string' && follower.userName.trim()
|
||||
? follower.userName.trim()
|
||||
: "Un utilisateur";
|
||||
: 'Un utilisateur'
|
||||
|
||||
const message = `${followerName} te suit maintenant`;
|
||||
const message = `${followerName} te suit maintenant`
|
||||
|
||||
await sendNotification({
|
||||
sender: followerId,
|
||||
receiver: userId,
|
||||
receiverCollection: "users",
|
||||
title: "Nouvel abonné",
|
||||
receiverCollection: 'users',
|
||||
title: 'Nouvel abonné',
|
||||
message,
|
||||
data: {
|
||||
type: ALERT_TYPE?.NEW_FOLLOWER,
|
||||
followerId,
|
||||
followerName,
|
||||
followerProfilePicture: follower?.profilePicture || "",
|
||||
followerProfilePicture: follower?.profilePicture || '',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
return null;
|
||||
}),
|
||||
);
|
||||
return null
|
||||
})
|
||||
)
|
||||
|
||||
return null;
|
||||
return null
|
||||
} catch (error) {
|
||||
console.log("[createNewFollowerNotification] error:", error);
|
||||
return error;
|
||||
console.log('[createNewFollowerNotification] error:', error)
|
||||
return error
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user