Skip to content

Instantly share code, notes, and snippets.

@devonChurch
Last active April 20, 2021 07:10
Show Gist options
  • Save devonChurch/dfa838a12d9dd08d1f68a7e4f36e452d to your computer and use it in GitHub Desktop.
Save devonChurch/dfa838a12d9dd08d1f68a7e4f36e452d to your computer and use it in GitHub Desktop.
Fetch, Flatten, Sanitise and Set Testimonial Items
const Firestore = require("@google-cloud/firestore");
const functions = require("firebase-functions");
const axios = require("axios");
const API_ENDPOINT = "https://services.languageperfect.com/json.rpc";
const API_METHOD = "nz.co.LanguagePerfect.Services.PortalsAsync.ControlPanel.NewsPortal.GetCommunityArticlesPublic"; // prettier-ignore
const FIRESTORE_COLLECTION = "testimonialsFiltered";
const FIRESTORE_PROJECT_ID = "testimonials-4d1e6";
const COUNTRIES = [
1, // International,
2, // New Zealand
3, // Australia
];
/**
* Get as many testimonial items as we can that are associated with the supplied
* `Country` code.
*
* @note We make sure to extract the items from the response payload before resolving
* this async sequence.
*/
const getRawitems = ({ Country }) =>
axios
.post(API_ENDPOINT, {
method: API_METHOD,
params: [
{
// @note We do not have an `Infinity` or "all" value here, so in order to get every item, we ask
// for an enormous set and take the values that were used to attempt the quota.
NumberOfArticles: 99999999,
DepartmentIDs: [],
Country,
},
],
})
.then((response) => response.data.result.Articles);
/**
* Strip down the Back-end item structure to a reduced "slim" payload for the Front-end.
*/
const sanitizeItems = (items) =>
items.map((item) => ({
// @note the original `ItemID` is changed to `id` when sanitising.
id: item.ItemID,
...[
"AuthorFirstName",
"AuthorSurname",
"CountryName",
"ImageURL",
"PlainTextMessage",
"PostDate",
"SchoolLatitude",
"SchoolLongitude",
"SchoolName",
"StateAbbreviation",
].reduce((acc, key) => ({ ...acc, [key]: item[key] }), {}),
}));
/**
* Setup and hold the testimonial collection in closure. `set` items onto the collection using their
* `id` as the primary index.
*
* @note a `set` will either "update" or "create" an item if the `id` does not exist in the collection.
*
* @see https://firebase.google.com/docs/firestore/manage-data/add-data#set_a_document
*/
const setItemInFirestore = (() => {
const firestoreCollection = new Firestore({
projectId: FIRESTORE_PROJECT_ID,
}).collection(FIRESTORE_COLLECTION);
return (item) => firestoreCollection.doc(`${item.id}`).set(item);
})();
const startSequence = async (context) => {
try {
// Get the testimonial items for each country (with independent async requests) and flatten the
// responses into a single "sanitized" item list.
const sanitizedItems = await Promise.all(
COUNTRIES.map((Country) => getRawitems({ Country }))
)
.then((...rawItems) => rawItems.flat(Infinity))
.then(sanitizeItems);
// Iterate through our fetch/flattened/sanitised item list and "set" them into our Firestore
await Promise.all(sanitizedItems.map(setItemInFirestore));
} catch (error) {
console.error(error);
}
};
// @see https://firebase.google.com/docs/functions/schedule-functions
// @see https://cloud.google.com/appengine/docs/standard/python/config/cronref
exports.scheduledFunction = functions.pubsub
.schedule("every 24 hours")
.onRun(startSequence);
@loucasg
Copy link

loucasg commented Apr 20, 2021

Correct codes are:

  1, // International,
  2, // New Zealand
  3, // Australia

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment