paradigm-core
Version:
Paradigm Core Modules
279 lines (215 loc) • 6.73 kB
JavaScript
const {
r, RootModel, ApplicationsPlugin: {ApplicationModel}
} = require('structure-core')
const {DocumentModel} = require('../../documents')
const AppleNewsAPI = require('../lib/apple-news-api')
/**
* AppleNewsArticleModel Class
*
* @public
* @class AppleNewsArticleModel
*/
module.exports = class AppleNewsArticleModel extends RootModel {
/**
* AppleNewsArticleModel constructor
*
* @public
* @constructor
* @param {Object} options - Options
*/
constructor(options = {}) {
super(Object.assign({}, {
table: 'apple_news_articles',
relations: {
belongsTo: [
{
node: 'documents',
link: {
foreignKey: 'documentId',
localKey: 'appleNewsArticleId'
},
joinTable: 'link_apple_news_articles_documents'
},
]
}
}, options))
}
/**
* Get or create an apple news client, configured with the channel for the
* current application
*
* @private
* @returns {Object} client - apple news 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 AppleNewsAPI({
channelId: app.appleNewsChannelId,
apiId: app.appleNewsApiId,
apiSecret: app.appleNewsApiSecret
})
this.client = client
return client
}
/**
* Get an apple news article by document ID
*
*
* @private
* @param {String} documentId - the document ID to fetch the apple news
* article of
* @returns {Object} apple news article document
*/
async getByDocumentId(documentId) {
let res = await r
.table('link_apple_news_articles_documents')
.getAll(documentId, {index: 'documentId'})
if (res.length === 0) {
return
}
return await this.getById(res[0].appleNewsArticleId)
}
/**
* Create or update an apple news article for a document.
*
* If an article already exists for the document, update it on Apple News and
* update the corresponding local apple news article document.
* If an article does not exist yet, create it on APple News and create a
* corresponding local apple news article document
*
* @public
* @param {String} documentId - the document ID to create or update for
* @returns {Object} the created or updated apple news article document
*/
async createOrUpdateForDocument(documentId) {
try {
const client = await this.getClient()
const appleNewsArticle = await this.getByDocumentId(documentId)
const documentModel = new DocumentModel({
organizationId: this.organizationId,
applicationId: this.applicationId,
logger: this.logger,
})
const articleJson = await documentModel.getAppleNewsFormat(documentId)
if (appleNewsArticle) {
let article
try {
article = await client.updateArticle(
appleNewsArticle.articleId,
appleNewsArticle.articleRevision,
articleJson.article,
articleJson.bundlesToUrls
)
} catch(e) {
// If we receive a WRONG_REVISION it's either because we have already
// updated the article or because our articleRevsion has become out
// of sync. Lets sync the article revision to ensure it is up to date.
if (e.apiError && e.apiError.code && e.apiError.code === 'WRONG_REVISION') {
this.logger.debug('Apple News Article has already been updated')
await this.syncArticleRevsion(appleNewsArticle)
return
} else {
throw e
}
}
this.logger.debug('Successfully updated apple news article', {
documentId,
articleId: article.articleId,
articleRevision: article.revision
})
return await RootModel.prototype.updateById.call(
this,
appleNewsArticle.id,
{
articleJson,
articleRevision: article.revision
}
)
} else {
const article = await client.createArticle(
articleJson.article,
articleJson.bundlesToUrls
)
this.logger.debug('Successfully created apple news article', {
documentId,
articleId: article.id,
articleRevision: article.revision
})
return await RootModel.prototype.create.call(
this,
{
documentId,
articleJson,
articleId: article.id,
articleRevision: article.revision
}
)
}
} catch(e) {
this.logger.error('Failed to createOrUpdateForDocument', {e})
throw e
}
}
/**
* Sync article revision for an apple news article of a document
*
*
* @private
* @param {String} appleNewsArticle - the apple news article to sync article revsion of
* @returns {Object} synced apple news article document
*/
async syncArticleRevsion(appleNewsArticle) {
const client = await this.getClient()
const article = await client.readArticle(appleNewsArticle.articleId)
return this.updateById(
appleNewsArticle.id,
{articleRevision: article.revision}
)
}
/**
* Delete an apple news article for a document.
*
* Delete the apple news article from Apple News and the corresponding local
* apple news article document.
*
* @public
* @param {String} documentId - the document ID to create or update for
*/
async deleteForDocument(documentId) {
try {
const client = await this.getClient()
const appleNewsArticle = await this.getByDocumentId(documentId)
if (!appleNewsArticle) {
return
}
try {
await client.deleteArticle(
appleNewsArticle.articleId
)
} catch(e) {
// The article may already have been deleted, in which case just ignore
// and continue
if (e.apiError && e.apiError.code && e.apiError.code === 'NOT_FOUND') {
this.logger.debug('Apple News Article has already been deleted')
} else {
throw e
}
}
this.logger.debug('Successfully deleted apple news article', {
documentId,
articleId: appleNewsArticle.articleId
})
await RootModel.prototype.deleteById.call(this, appleNewsArticle.id)
} catch(e) {
this.logger.error('Failed to deleteForDocument', {e})
throw e
}
}
}