Skip to content

Commit

Permalink
Merge branch 'final-changes' into design-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nethmalgunawardhana authored Dec 1, 2024
2 parents 5c8d04d + 3499fb8 commit 2c278fa
Show file tree
Hide file tree
Showing 25 changed files with 642 additions and 524 deletions.
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,10 @@ next-env.d.ts
# firebase emulator logs
ui-debug.log
firebase-debug.log
firestore-debug.log
firestore-debug.log
# next-video
public/videos/*
!public/videos/*.json
!public/videos/*.js
!public/videos/*.ts
public/_next-video
1 change: 1 addition & 0 deletions functions/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ module.exports = {
"import/no-commonjs": "off", // Allow 'require' in ESM, commonjs modules
// Change linebreak-style from error to warning
"linebreak-style": ["warn", "unix"],
"max-len": ["error", {"code": 120}],
},
};
122 changes: 122 additions & 0 deletions functions/src/companyDataAggregator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {db} from "./firebaseSetup";
import {FieldValue} from "firebase-admin/firestore";
import {
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
} from "firebase-functions/v2/firestore";
import {https, logger} from "firebase-functions";

const REGION = "asia-southeast1";

const AGGREGATED_COMPANIES_DOC_PATH = "metadata/agregatedCompanies";
const COMPANIES_COLLECTION_PATH = "campaigns/rur-25/companies";


// Fields to be aggregated
const SELECTED_FIELDS = [
"companyId",
"name",
"description",
"logoUrl",
"preferredFields",
"qualitiesToLook",
"dataConfirmed",
];


const filterSelectedFields = (data: Record<string, any>): Record<string, any> =>
Object.fromEntries(
Object.entries(data).filter(([key]) => SELECTED_FIELDS.includes(key))
);


export const manualAggregateCompanies = https.onRequest({
region: REGION,
}, async (req, res) => {
try {
const aggregatedCompanies: Record<string, any> = {};
const companiesSnapshot = await db.collection(COMPANIES_COLLECTION_PATH).get();

companiesSnapshot.forEach((doc) => {
// Include only if dataConfirmed is true
if (doc.data().dataConfirmed) {
aggregatedCompanies[doc.id] = filterSelectedFields(doc.data());
}
});

await db.doc(AGGREGATED_COMPANIES_DOC_PATH)
.set({companies: aggregatedCompanies});

logger.info("Manual aggregation completed:", AGGREGATED_COMPANIES_DOC_PATH);
res.status(200).send({message: "Manual aggregation completed."});
} catch (error) {
logger.error("Error during manual aggregation:", error);
res.status(500).send({error: "Internal Server Error"});
}
});


export const incrementalAggregateCompanies = {
onCreate: onDocumentCreated({
document: COMPANIES_COLLECTION_PATH + "/{docId}",
region: REGION,
}, async (event) => {
try {
const newData = event.data?.data();
if (!newData?.dataConfirmed) return;

const newDoc = filterSelectedFields(newData);
const docId = event.params.docId;

// Update the aggregated document with the new data
await db.doc(AGGREGATED_COMPANIES_DOC_PATH).update({
[`companies.${docId}`]: newDoc,
});

logger.info(`Incrementally added document: ${docId}`);
} catch (error) {
logger.error("Error during onCreate incremental update:", error);
}
}),

onUpdate: onDocumentUpdated({
document: COMPANIES_COLLECTION_PATH + "/{docId}",
region: REGION,
}, async (event) => {
try {
const updatedData = event.data?.after.data();
if (!updatedData?.dataConfirmed) return;

const updatedDoc = filterSelectedFields(updatedData);
const docId = event.params.docId;

// Update the aggregated document with the updated data
await db.doc(AGGREGATED_COMPANIES_DOC_PATH).update({
[`companies.${docId}`]: updatedDoc,
});

logger.info(`Incrementally updated document: ${docId}`);
} catch (error) {
logger.error("Error during onUpdate incremental update:", error);
}
}),

onDelete: onDocumentDeleted({
document: COMPANIES_COLLECTION_PATH + "/{docId}",
region: REGION,
}, async (event) => {
try {
const docId = event.params.docId;

// Remove the deleted document from the aggregated document
await db.doc(AGGREGATED_COMPANIES_DOC_PATH).update({
[`companies.${docId}`]: FieldValue.delete(),
});

logger.info(`Incrementally deleted document: ${docId}`);
} catch (error) {
logger.error("Error during onDelete incremental update:", error);
}
}),
};
6 changes: 6 additions & 0 deletions functions/src/firebaseSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {initializeApp} from "firebase-admin/app";
import {getFirestore} from "firebase-admin/firestore";

// Initialize Firebase
initializeApp();
export const db = getFirestore();
78 changes: 19 additions & 59 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,26 @@
import {initializeApp} from "firebase-admin/app";
import {getFirestore} from "firebase-admin/firestore";
import {createInfoTriggers} from "./infoAggregator";
import {
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
} from "firebase-functions/v2/firestore";
import {logger} from "firebase-functions";
incrementalAggregateCompanies,
manualAggregateCompanies,
} from "./companyDataAggregator";

initializeApp();
const db = getFirestore();
// Exporting triggers for /info-sponsors and /info-timeline collections
const sponsorsTriggers = createInfoTriggers("info-sponsors");
const timelineTriggers = createInfoTriggers("info-timeline");

// Path for the aggregated document
const AGGREGATED_DOC_PATH = "metadata/aggregatedInfo";
export const infoSponsorsOnCreate = sponsorsTriggers.onCreate;
export const infoSponsorsOnUpdate = sponsorsTriggers.onUpdate;
export const infoSponsorsOnDelete = sponsorsTriggers.onDelete;

// Aggregates data from /info-sponsors and /info-timeline into a single document
const aggregateData = async () => {
try {
const aggregatedData: {
"info-sponsors": Record<string, unknown>;
"info-timeline": Record<string, unknown>;
} = {"info-sponsors": {}, "info-timeline": {}};
export const infoTimelineOnCreate = timelineTriggers.onCreate;
export const infoTimelineOnUpdate = timelineTriggers.onUpdate;
export const infoTimelineOnDelete = timelineTriggers.onDelete;

// Aggregate data from info-sponsors
const sponsorsSnapshot = await db.collection("info-sponsors").get();
sponsorsSnapshot.forEach((doc) => {
aggregatedData["info-sponsors"][doc.id] = doc.data();
});

// Aggregate data from info-timeline
const timelineSnapshot = await db.collection("info-timeline").get();
timelineSnapshot.forEach((doc) => {
aggregatedData["info-timeline"][doc.id] = doc.data();
});
// Exporting Firestore triggers for incremental company aggregation
export const companyOnCreate = incrementalAggregateCompanies.onCreate;
export const companyOnUpdate = incrementalAggregateCompanies.onUpdate;
export const companyOnDelete = incrementalAggregateCompanies.onDelete;

// Save the aggregated data to the Firestore document
await db.doc(AGGREGATED_DOC_PATH).set(aggregatedData);
logger.info("Successfully aggregated data into:", AGGREGATED_DOC_PATH);
} catch (error) {
logger.error("Error aggregating data:", error);
}
};

// Helper to create triggers for a given collection
const createTriggers = (collectionPath: string) => {
return {
onCreate: onDocumentCreated(`${collectionPath}/{docId}`, async (event) => {
logger.info(`Document created in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
onUpdate: onDocumentUpdated(`${collectionPath}/{docId}`, async (event) => {
logger.info(`Document updated in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
onDelete: onDocumentDeleted(`${collectionPath}/{docId}`, async (event) => {
logger.info(`Document deleted in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
};
};

// Export triggers for /info-sponsors
export const aggregateInfoSponsors = createTriggers("info-sponsors");

// Export triggers for /info-timeline
export const aggregateInfoTimeline = createTriggers("info-timeline");
// Exporting HTTP function for manual aggregation
export const aggregateCompaniesManually = manualAggregateCompanies;
61 changes: 61 additions & 0 deletions functions/src/infoAggregator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {db} from "./firebaseSetup";
import {
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
} from "firebase-functions/v2/firestore";
import {logger} from "firebase-functions";

const REGION = "asia-southeast1";

// Path for the aggregated document
const AGGREGATED_DOC_PATH = "metadata/aggregatedInfo";

// Aggregates data from /info-sponsors and /info-timeline into a single document
const aggregateData = async () => {
try {
const aggregatedData: {
"info-sponsors": Record<string, unknown>;
"info-timeline": Record<string, unknown>;
} = {"info-sponsors": {}, "info-timeline": {}};

// Aggregate data from info-sponsors
const sponsorsSnapshot = await db.collection("info-sponsors").get();
sponsorsSnapshot.forEach((doc) => {
aggregatedData["info-sponsors"][doc.id] = doc.data();
});

// Aggregate data from info-timeline
const timelineSnapshot = await db.collection("info-timeline").get();
timelineSnapshot.forEach((doc) => {
aggregatedData["info-timeline"][doc.id] = doc.data();
});

// Save the aggregated data to the Firestore document
await db.doc(AGGREGATED_DOC_PATH).set(aggregatedData);
logger.info("Successfully aggregated data into:", AGGREGATED_DOC_PATH);
} catch (error) {
logger.error("Error aggregating data:", error);
}
};

// Helper to create triggers for a given collection
export const createInfoTriggers = (collectionPath: string) => {
return {
onCreate: onDocumentCreated({document: `${collectionPath}/{docId}`, region: REGION},
async (event) => {
logger.info(`Document created in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
onUpdate: onDocumentUpdated({document: `${collectionPath}/{docId}`, region: REGION},
async (event) => {
logger.info(`Document updated in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
onDelete: onDocumentDeleted({document: `${collectionPath}/{docId}`, region: REGION},
async (event) => {
logger.info(`Document deleted in ${collectionPath}:`, event.params.docId);
await aggregateData();
}),
};
};
2 changes: 1 addition & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ const nextConfig: NextConfig = {
},
};

export default nextConfig;
export default nextConfig;
Loading

0 comments on commit 2c278fa

Please sign in to comment.