const admin = require("firebase-admin"); const { onDocumentWritten } = require("firebase-functions/firestore"); const _ = require("lodash"); const { refList, db } = require("../index"); const { getSunoTimestamps } = require("./lyrics"); const { deleteFolder } = require("../helpers/firebase"); const { buildMonthKey } = require("../helpers/stats"); exports.onProjectWritten = onDocumentWritten( "projects/{projectId}", async (projectSnap) => { try { const { projectId } = projectSnap.params; const beforeData = projectSnap?.data?.before?.data() || null; const afterData = projectSnap?.data?.after?.data() || null; if (!afterData) { const { userId } = beforeData || {}; if (userId) { await deleteFolder(`users/${userId}/projects/${projectId}/`); } const snapshot = await refList.tasks .where("projectId", "==", projectId) .get(); if (!snapshot.empty) { const batch = db.batch(); snapshot.forEach((doc) => { batch.delete(doc.ref); }); await batch.commit(); } return null; } else if (!beforeData) { //song create } else { if (!beforeData?.songUrl && afterData?.songUrl) { await getSunoTimestamps(projectId); await refList.projects.doc(projectId).update({ hasSong: true }); } if (!beforeData?.playbackUrl && afterData?.playbackUrl) { await refList.projects.doc(projectId).update({ hasPlayback: true }); } } const beforeViews = _.toFinite(_.get(beforeData, "views", 0)); const afterViews = _.toFinite(_.get(afterData, "views", 0)); const delta = afterViews - beforeViews; if (delta > 0) { const userIdRaw = _.get(afterData, "userId", null); const userId = _.isString(userIdRaw) && _.trim(userIdRaw).length ? _.trim(userIdRaw) : null; const now = admin.firestore.Timestamp.now(); const monthKey = buildMonthKey(now); const statsDocRef = refList.projectStreamStats .doc(projectId) .collection("monthlyListens") .doc(monthKey); const totalsDocRef = refList.projectStreamStatsMonthlyTotals.doc(monthKey); await db.runTransaction(async (transaction) => { const statsSnapshot = await transaction.get(statsDocRef); const totalsSnapshot = await transaction.get(totalsDocRef); const updatePayload = { projectId, userId, monthKey, updatedAt: now, lastStreamAt: now, lastDelta: delta, streams: admin.firestore.FieldValue.increment(delta), }; const hasFirstStream = statsSnapshot.exists && statsSnapshot.data()?.firstStreamAt; if (!hasFirstStream) { updatePayload.firstStreamAt = now; } transaction.set(statsDocRef, updatePayload, { merge: true }); const totalsUpdatePayload = { monthKey, updatedAt: now, lastStreamAt: now, lastDelta: delta, totalStreams: admin.firestore.FieldValue.increment(delta), }; const totalsHasFirstStream = totalsSnapshot.exists && totalsSnapshot.data()?.firstStreamAt; if (!totalsHasFirstStream) { totalsUpdatePayload.firstStreamAt = now; } transaction.set(totalsDocRef, totalsUpdatePayload, { merge: true }); }); } return null; } catch (error) { console.log("onProjectViewsIncrement error", { message: error?.message || String(error || ""), }); return null; } }, );