UNPKG

paradigm-facebook-ia

Version:
262 lines (202 loc) 6.5 kB
const r = require('structure-driver') const RootModel = require('structure-root-model') const {DocumentModel} = require('paradigm-documents') const {ApplicationModel} = require('structure-applications') const CheckImportJob = require('../jobs/check-import') const FacebookIAAPI = require('../lib/facebook-ia-api') /** * FacebookInstantArticleModel Class * * @public * @class FacebookInstantArticleModel */ class FacebookInstantArticleModel extends RootModel { /** * FacebookInstantArticleModel constructor * * @public * @constructor * @param {Object} options - Options */ constructor(options = {}) { super(Object.assign({}, { table: 'facebook_instant_articles', relations: { belongsTo: [ { node: 'documents', link: { foreignKey: 'documentId', localKey: 'facebookInstantArticleId' }, joinTable: 'link_facebook_instant_articles_documents' }, ] } }, options)) } /** * Get or create a Facebook API client, configured with the page and access * token for the current application * * @private * @returns {Object} client - Facebook API client instance */ async getClient() { if (this.client) { return this.client } const applicationModel = new ApplicationModel({ organizationId: this.organizationId, logger: this.logger, }) const app = await applicationModel.getById(this.applicationId) const client = new FacebookIAAPI( app.facebook.pageId, app.facebook.pageAccessToken ) this.client = client return client } /** * Get a facebook instant article by document ID * * * @private * @param {String} documentId - the document ID to fetch the fb instant * article of * @returns {Object} facebook instant article document */ async getByDocumentId(documentId) { let res = await r .table('link_facebook_instant_articles_documents') .getAll(documentId, {index: 'documentId'}) if (res.length === 0) { return } return await this.getById(res[0].facebookInstantArticleId) } /** * Create or update an facebook instant article for a document. * * If an article already exists for the document, update it on Facebook and * update the corresponding local facebook instant article document. * If an article does not exist yet, create it on Facebook and create a * corresponding local facebook instant article document * * @public * @param {String} documentId - the document ID to create or update for * @returns {Object} the created or updated facebook instant article document */ async createOrUpdateForDocument(documentId) { try { const client = await this.getClient() let fbia = await this.getByDocumentId(documentId) const documentModel = new DocumentModel({ organizationId: this.organizationId, applicationId: this.applicationId, logger: this.logger, }) const checkImportJob = new CheckImportJob({ organizationId: this.organizationId, applicationId: this.applicationId, logger: this.logger }) const {markup, canonicalUrl} = await documentModel.getFacebookIAFormat( documentId ) if (fbia) { // If the article hasn't actually changed, just return if (fbia.canonicalUrl === canonicalUrl && fbia.markup === markup) { return fbia } // The article has not finished importing. Throw an error so that the // job retries. if (fbia.importStatus === 'importing') { throw `Article not finished importing, can't update yet` } // If the canonical URL has changed, delete the article for the old URL if (fbia.canonicalUrl !== canonicalUrl && fbia.importStatus === 'success') { client.deleteArticle(fbia.articleId) } const article = await client.createArticle(markup) this.logger.debug('Successfully updated facebook instant article', { documentId, canonicalUrl, markup, articleImportId: article.id, }) fbia = await RootModel.prototype.updateById.call( this, fbia.id, { markup, canonicalUrl, articleImportId: article.id, articleId: null, importStatus: 'importing', } ) } else { const article = await client.createArticle(markup) this.logger.debug('Successfully created facebook instant article', { documentId, articleImportId: article.id, canonicalUrl }) fbia = await RootModel.prototype.create.call( this, { documentId, markup, canonicalUrl, articleImportId: article.id, importStatus: 'importing', } ) } const now = new Date() var oneMinute = new Date(now.getTime() + (60 * 1000)) checkImportJob.queue({fbia}, {delayDate: oneMinute}) return fbia } catch(e) { this.logger.error('Failed to createOrUpdateForDocument', {e}) throw e } } /** * Delete an facebook instant article for a document. * * Delete the facebook instant article from Facebook and the corresponding * local facebook instant article document. * * @public * @param {String} documentId - the document ID to create or update for */ async deleteForDocument(documentId) { try { const client = await this.getClient() const fbia = await this.getByDocumentId(documentId) if (!fbia) { return } // The article has not finished importing yet. Throw an error so that the // job retries. if (fbia.importStatus === 'importing') { throw `Article not finished importing, can't delete yet` } if (fbia.importStatus !== 'failed') { await client.deleteArticle(fbia.articleId) this.logger.debug('Successfully deleted facebook instant article', { documentId, articleId: fbia.articleId }) } await RootModel.prototype.deleteById.call(this, fbia.id) } catch(e) { this.logger.error('Failed to deleteForDocument', {e}) throw e } } } module.exports = FacebookInstantArticleModel