tanam
Version:
Pluggable CMS for Firebase
167 lines • 8.99 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const taskService = require("../services/task.service");
exports.onCreateDocumentRequestRendering = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onCreate((snap, context) => __awaiter(this, void 0, void 0, function* () {
const siteId = context.params.siteId;
const document = snap.data();
if (!document.standalone || document.status !== 'published') {
console.log(`The document is not published and standalone and is not managed by cache. Do nothing.`);
return null;
}
return taskService.createCache(siteId, document.url);
}));
exports.onDeleteDocumentCleanUp = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onDelete((snap, context) => __awaiter(this, void 0, void 0, function* () {
const siteId = context.params.siteId;
const documentId = context.params.documentId;
const document = snap.data();
const referencingDocs = yield admin.firestore()
.collection('tanam').doc(siteId)
.collection('documents')
.where('dependencies', 'array-contains', documentId)
.get();
const promises = [taskService.deleteCache(siteId, document.url)];
for (const doc of referencingDocs.docs) {
promises.push(taskService.updateCache(siteId, doc.data().url));
}
return Promise.all(promises);
}));
exports.onUpdateDocumentRequestRendering = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onUpdate((change, context) => __awaiter(this, void 0, void 0, function* () {
const siteId = context.params.siteId;
const documentId = context.params.documentId;
const entryBefore = change.before.data();
const entryAfter = change.after.data();
if (['data', 'title', 'url', 'tags', 'standalone', 'status', 'published'].every(key => JSON.stringify(entryBefore[key]) === JSON.stringify(entryAfter[key]))) {
console.log(`Document changes doesn't require it to be re-rendered.`);
return null;
}
console.log(JSON.stringify({ siteId, documentId, urlBefore: entryBefore.url, urlAfter: entryAfter.url }));
const referencingDocs = yield admin.firestore()
.collection('tanam').doc(siteId)
.collection('documents')
.where('dependencies', 'array-contains', documentId)
.where('rendered', '<', entryAfter.updated)
.get();
const promises = [];
promises.push(taskService.updateCache(siteId, entryBefore.url));
promises.push(taskService.updateCache(siteId, entryAfter.url));
for (const doc of referencingDocs.docs) {
const referringDocument = doc.data();
console.log(`Referenced by document id=${referringDocument.id}, url=${referringDocument.url}`);
promises.push(taskService.updateCache(siteId, referringDocument.url));
}
return Promise.all(promises);
}));
exports.updateDocumentStatusCounter = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onWrite((change, context) => {
const siteId = context.params.siteId;
const entryBefore = change.before.data() || {};
const entryAfter = change.after.data() || {};
if (change.before.exists && change.after.exists && entryAfter.status === entryBefore.status) {
console.log(`Document status unchanged. No counters updated.`);
return null;
}
const documentType = entryAfter.documentType || entryBefore.documentType;
console.log(`Updating counters for ${documentType}`);
const updates = {};
if (change.before.exists) {
updates[`documentCount.${entryBefore.status}`] = admin.firestore.FieldValue.increment(-1);
}
if (change.after.exists) {
updates[`documentCount.${entryAfter.status}`] = admin.firestore.FieldValue.increment(1);
}
return admin.firestore()
.collection('tanam').doc(siteId)
.collection('document-types').doc(documentType)
.update(updates);
});
exports.saveRevision = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onUpdate((change) => {
const entryBefore = change.before.data();
console.log(`Saving revision ${entryBefore.revision} of ${change.before.ref.path}`);
return change.before.ref.collection('revisions').doc(`${entryBefore.id}+${entryBefore.revision}`).set(entryBefore);
});
exports.deleteRevisions = functions.firestore.document('tanam/{siteId}/documents/{documentId}').onDelete((snap) => __awaiter(this, void 0, void 0, function* () {
console.log(`Deleting all revisions of ${snap.ref.path}`);
const revs = yield snap.ref.collection('revisions').get();
const promises = [];
const batchDeletes = [];
for (let i = 0; i < revs.docs.length; i++) {
const doc = revs.docs[i];
if ((i % 500) === 0) {
batchDeletes.push(admin.firestore().batch());
}
const batchNum = batchDeletes.length - 1;
console.log(`Batch delete #${batchNum} (${i + 1}/500): ${doc.id}`);
batchDeletes[batchNum].delete(doc.ref);
}
batchDeletes.forEach((batchWrite) => {
promises.push(batchWrite.commit());
});
return Promise.all(promises);
}));
exports.deleteFieldReferences = functions.firestore.document('tanam/{siteId}/{contentType}/{fileId}').onDelete((snap, context) => __awaiter(this, void 0, void 0, function* () {
const siteId = context.params.siteId;
const contentType = context.params.contentType;
if (!['documents', 'files'].some(c => c === contentType)) {
console.log(`Deleted a ${contentType} document. Nothing to do for this function.`);
return null;
}
const promises = [];
const deletedDoc = snap.data();
console.log(`Looking through all document types to find reference fields.`);
const documentTypeDocs = yield admin.firestore()
.collection('tanam').doc(siteId)
.collection('document-types')
.get();
for (const documentTypeDoc of documentTypeDocs.docs) {
const documentType = documentTypeDoc.data();
const fieldNames = documentType.fields
.filter((field) => field.type === 'image' || field.type === 'document-reference')
.map(field => field.key);
console.log(`Document type "${documentType.id}" has ${fieldNames.length} file references`);
for (const fieldName of fieldNames) {
console.log(`Searching and replacing all "${documentType.id}" documents with reference: ${fieldName}`);
const referringDocumentsQuery = yield admin.firestore()
.collection('tanam').doc(siteId)
.collection('documents')
.where(`data.${fieldName}`, '==', deletedDoc.id)
.get();
console.log(`Found ${referringDocumentsQuery.docs.length} documents that matched: data.${fieldName} == ${deletedDoc.id}`);
// TODO: batchwrite for better performance and manage > 500 references
for (const doc of referringDocumentsQuery.docs) {
console.log(`Clearing reference "${fieldName}" in document data for id: ${doc.id}`);
promises.push(admin.firestore().runTransaction((trx) => __awaiter(this, void 0, void 0, function* () {
const trxDoc = yield trx.get(doc.ref);
return trx.update(doc.ref, {
revision: trxDoc.data().revision + 1,
[`data.${fieldName}`]: null
});
})));
}
}
}
return promises;
}));
exports.publishScheduledDocuments = functions.pubsub.schedule('every 5 minutes').onRun((context) => __awaiter(this, void 0, void 0, function* () {
const unpublishedDocuments = yield admin.firestore()
.collection('tanam').doc(process.env.GCLOUD_PROJECT)
.collection('documents')
.where('status', '==', 'scheduled')
.where('published', '<', admin.firestore.Timestamp.fromDate(new Date()))
.get();
console.log(`Found ${unpublishedDocuments.docs.length} that are due for publishing`);
const promises = [];
for (const doc of unpublishedDocuments.docs) {
promises.push(doc.ref.update({ status: 'published' }));
}
return Promise.all(promises);
}));
//# sourceMappingURL=documents.js.map