mirror of
https://github.com/urosran/cally.git
synced 2025-07-17 02:25:10 +00:00
Batch updates
This commit is contained in:
@ -293,47 +293,152 @@ exports.sendNotificationOnEventCreation = functions.firestore
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Store batches in Firestore instead of memory
|
||||||
|
async function addToUpdateBatch(eventData, eventId) {
|
||||||
|
const batchId = `${eventData.familyId}_${eventData.lastModifiedBy}`;
|
||||||
|
const batchRef = admin.firestore().collection('UpdateBatches').doc(batchId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await admin.firestore().runTransaction(async (transaction) => {
|
||||||
|
const batchDoc = await transaction.get(batchRef);
|
||||||
|
|
||||||
|
if (!batchDoc.exists) {
|
||||||
|
// Create new batch
|
||||||
|
transaction.set(batchRef, {
|
||||||
|
familyId: eventData.familyId,
|
||||||
|
lastModifiedBy: eventData.lastModifiedBy,
|
||||||
|
externalOrigin: eventData.externalOrigin,
|
||||||
|
events: [{
|
||||||
|
id: eventId,
|
||||||
|
title: eventData.title,
|
||||||
|
startDate: eventData.startDate
|
||||||
|
}],
|
||||||
|
createdAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
processed: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Update existing batch
|
||||||
|
const existingEvents = batchDoc.data().events || [];
|
||||||
|
transaction.update(batchRef, {
|
||||||
|
events: [...existingEvents, {
|
||||||
|
id: eventId,
|
||||||
|
title: eventData.title,
|
||||||
|
startDate: eventData.startDate
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding to update batch:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.onEventUpdate = functions.firestore
|
exports.onEventUpdate = functions.firestore
|
||||||
.document('Events/{eventId}')
|
.document('Events/{eventId}')
|
||||||
.onUpdate(async (change, context) => {
|
.onUpdate(async (change, context) => {
|
||||||
const beforeData = change.before.data();
|
const beforeData = change.before.data();
|
||||||
const afterData = change.after.data();
|
const afterData = change.after.data();
|
||||||
const {familyId, title, lastModifiedBy} = afterData;
|
const {familyId, title, lastModifiedBy, externalOrigin, startDate} = afterData;
|
||||||
|
|
||||||
// Skip if no meaningful changes
|
|
||||||
if (JSON.stringify(beforeData) === JSON.stringify(afterData)) {
|
if (JSON.stringify(beforeData) === JSON.stringify(afterData)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get push tokens excluding the user who made the change
|
await addToUpdateBatch({
|
||||||
const pushTokens = await getPushTokensForFamily(familyId, lastModifiedBy);
|
|
||||||
|
|
||||||
const message = `Event "${title}" has been updated`;
|
|
||||||
await sendNotifications(pushTokens, {
|
|
||||||
title: "Event Updated",
|
|
||||||
body: message,
|
|
||||||
data: {
|
|
||||||
type: 'event_update',
|
|
||||||
eventId: context.params.eventId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store notification in Firestore
|
|
||||||
await storeNotification({
|
|
||||||
type: 'event_update',
|
|
||||||
familyId,
|
familyId,
|
||||||
content: message,
|
title,
|
||||||
eventId: context.params.eventId,
|
lastModifiedBy,
|
||||||
excludedUser: lastModifiedBy,
|
externalOrigin,
|
||||||
timestamp: admin.firestore.FieldValue.serverTimestamp(),
|
startDate
|
||||||
date: eventData.startDate
|
}, context.params.eventId);
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending event update notification:', error);
|
console.error('Error in onEventUpdate:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Separate function to process batches
|
||||||
|
exports.processUpdateBatches = functions.pubsub
|
||||||
|
.schedule('every 1 minutes')
|
||||||
|
.onRun(async (context) => {
|
||||||
|
const batchesRef = admin.firestore().collection('UpdateBatches');
|
||||||
|
|
||||||
|
// Find unprocessed batches older than 5 seconds
|
||||||
|
const cutoff = new Date(Date.now() - 5000);
|
||||||
|
const snapshot = await batchesRef
|
||||||
|
.where('processed', '==', false)
|
||||||
|
.where('createdAt', '<=', cutoff)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
const processPromises = snapshot.docs.map(async (doc) => {
|
||||||
|
const batchData = doc.data();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const pushTokens = await getPushTokensForFamily(
|
||||||
|
batchData.familyId,
|
||||||
|
batchData.lastModifiedBy
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pushTokens.length) {
|
||||||
|
let message;
|
||||||
|
if (batchData.externalOrigin) {
|
||||||
|
message = `Calendar sync completed: ${batchData.events.length} events have been updated`;
|
||||||
|
} else {
|
||||||
|
message = batchData.events.length === 1
|
||||||
|
? `Event "${batchData.events[0].title}" has been updated`
|
||||||
|
: `${batchData.events.length} events have been updated`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await sendNotifications(pushTokens, {
|
||||||
|
title: batchData.externalOrigin ? "Calendar Sync Complete" : "Events Updated",
|
||||||
|
body: message,
|
||||||
|
data: {
|
||||||
|
type: 'event_update',
|
||||||
|
count: batchData.events.length
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await storeNotification({
|
||||||
|
type: 'event_update',
|
||||||
|
familyId: batchData.familyId,
|
||||||
|
content: message,
|
||||||
|
excludedUser: batchData.lastModifiedBy,
|
||||||
|
timestamp: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
count: batchData.events.length,
|
||||||
|
date: batchData.events[0].startDate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark batch as processed
|
||||||
|
await doc.ref.update({
|
||||||
|
processed: true,
|
||||||
|
processedAt: admin.firestore.FieldValue.serverTimestamp()
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing batch ${doc.id}:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(processPromises);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cleanup old batches
|
||||||
|
exports.cleanupUpdateBatches = functions.pubsub
|
||||||
|
.schedule('every 24 hours')
|
||||||
|
.onRun(async (context) => {
|
||||||
|
const batchesRef = admin.firestore().collection('UpdateBatches');
|
||||||
|
const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
const oldBatches = await batchesRef
|
||||||
|
.where('processedAt', '<=', dayAgo)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
const deletePromises = oldBatches.docs.map(doc => doc.ref.delete());
|
||||||
|
await Promise.all(deletePromises);
|
||||||
|
});
|
||||||
|
|
||||||
// Upcoming Event Reminders
|
// Upcoming Event Reminders
|
||||||
exports.checkUpcomingEvents = functions.pubsub
|
exports.checkUpcomingEvents = functions.pubsub
|
||||||
.schedule('every 5 minutes')
|
.schedule('every 5 minutes')
|
||||||
|
Reference in New Issue
Block a user