functions

This commit is contained in:
Thomas Demirdjian
2025-11-03 13:47:07 +01:00
parent 460c91f1e6
commit 7b3a47090d
16 changed files with 23868 additions and 2399 deletions
+90 -106
View File
@@ -1,69 +1,12 @@
const admin = require("firebase-admin");
const { onDocumentWritten } = require("firebase-functions/firestore");
const { refList } = require("../index");
const _ = require("lodash");
const { refList, db } = require("../index");
const { getSunoTimestamps } = require("./lyrics");
const { deleteFolder } = require("../helpers/firebase");
const { buildMonthKey } = require("../helpers/stats");
const firestore = admin.firestore();
const buildMonthKey = (timestamp) => {
const date = timestamp.toDate();
const year = date.getUTCFullYear();
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
return `${year}-${month}`;
};
exports.onProjectUpdate = onDocumentWritten(
"projects/{projectId}",
async (projectSnap) => {
try {
const { projectId } = projectSnap.params;
const currentData = projectSnap?.data?.after?.data() || null;
const previousData = projectSnap?.data?.before?.data() || null;
if (!previousData?.songUrl && currentData?.songUrl) {
await getSunoTimestamps(projectId);
}
if (!currentData) {
const { userId } = previousData || {};
//delete folder
await deleteFolder(`users/${userId}/projects/${projectId}/`);
//delete tasks
const snapshot = await refList.tasks
.where("projectId", "==", projectId)
.get();
if (snapshot.empty) return null;
const batch = admin.firestore().batch();
snapshot.forEach((doc) => {
batch.delete(doc.ref);
});
await batch.commit();
} else {
if (previousData) {
// edit
if (!previousData?.songUrl && currentData?.songUrl) {
await refList.projects.doc(projectId).update({
hasSong: true,
});
}
if (!previousData?.playbackUrl && currentData?.playbackUrl) {
await refList.projects.doc(projectId).update({
hasPlayback: true,
});
}
}
}
} catch (e) {
console.log(e);
}
}
);
exports.onProjectViewsIncrement = onDocumentWritten(
exports.onProjectWritten = onDocumentWritten(
"projects/{projectId}",
async (projectSnap) => {
try {
@@ -71,53 +14,94 @@ exports.onProjectViewsIncrement = onDocumentWritten(
const beforeData = projectSnap?.data?.before?.data() || null;
const afterData = projectSnap?.data?.after?.data() || null;
if (!afterData) return null;
if (!afterData) {
const { userId } = beforeData || {};
const beforeViews =
typeof beforeData?.views === "number" && Number.isFinite(beforeData.views)
? beforeData.views
: 0;
const afterViews =
typeof afterData?.views === "number" && Number.isFinite(afterData.views)
? afterData.views
: 0;
const delta = afterViews - beforeViews;
if (delta <= 0) return null;
const userId =
typeof afterData?.userId === "string" && afterData.userId.trim().length
? afterData.userId.trim()
: null;
const now = admin.firestore.Timestamp.now();
const monthKey = buildMonthKey(now);
const statsDocRef = firestore
.collection("projectStreamStats")
.doc(projectId)
.collection("monthly")
.doc(monthKey);
await firestore.runTransaction(async (transaction) => {
const statsSnapshot = await transaction.get(statsDocRef);
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;
if (userId) {
await deleteFolder(`users/${userId}/projects/${projectId}/`);
}
transaction.set(statsDocRef, updatePayload, { merge: true });
});
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) {
@@ -126,5 +110,5 @@ exports.onProjectViewsIncrement = onDocumentWritten(
});
return null;
}
}
},
);