UNPKG

paradigm-channels

Version:
608 lines (444 loc) 15.1 kB
const {DigitalAssetModel} = require('structure-digital-assets') const paradigmErrorCodes = require('paradigm-error-codes') const r = require('structure-driver') const RootModel = require('structure-root-model') const structureErrorCodes = require('structure-error-codes') /** * ChannelModel Class * * @public * @class ChannelModel */ class ChannelModel extends RootModel { /** * ChannelModel constructor * * @public * @constructor * @param {Object} options - Options */ constructor(options = {}) { super(Object.assign({}, { table: 'channels', relations: { hasManyAndBelongsTo: [ { node: 'channels', link: { foreignKey: 'channelParentId', localKey: 'channelChildId' }, joinTable: 'link_channels_channels' } ] } }, options)) } getAll(ids = [], options = {}) { const applicationId = this.applicationId || options.applicationId return new Promise( async (resolve, reject) => { try { let query = r .table(this.table) if(ids.length > 0) { query = query .getAll(r.args(ids)) } else { query = query .getAll(applicationId, {index: 'applicationId'}) .filter(function(doc) { return doc('status').eq('active') }) } const channels = await query.run() resolve(channels) } catch(e) { this.logger.error(e) reject(e) } }) } getBySlug(slug, options = {}) { const applicationId = this.applicationId || options.applicationId return new Promise( async (resolve, reject) => { try { const doc = await r .table(this.table) .getAll([slug, applicationId], {index: 'link_channelSlug_applicationId'}) if(doc.length > 0) { return resolve(doc[0]) } resolve(false) } catch(e) { this.logger.error(e) reject(e) } }) } getAllResources(params = {}, query = {}, options = {}) { const applicationId = this.applicationId || options.applicationId const id = params.id const ignoreDocumentIds = (query.ignoreDocumentIds) ? ((query.ignoreDocumentIds instanceof Array) ? query.ignoreDocumentIds : query.ignoreDocumentIds.split(',')) : [] const organizationId = this.organizationId || options.organizationId const slug = params.slug const daModel = new DigitalAssetModel({ applicationId, logger: this.logger, organizationId }) const {DocumentModel} = require('paradigm-documents') // prevent circular dep const documentModel = new DocumentModel({ applicationId, logger: this.logger, organizationId }) return new Promise( async (resolve, reject) => { try { let channel if(id) { channel = await this.getById(id) } else { channel = await this.getBySlug(slug, { applicationId, organizationId }) } if(!channel) { return reject(paradigmErrorCodes('CHANNEL_INVALID', { applicationId, id, organizationId, slug })) } if(!(channel.resources instanceof Array)) channel.resources = [] let map = new Map() const categoriesMap = new Map() const categoryIds2SlugMap = {} const categoriesSlugsMap = new Map() const categoriesList = await r .table('categories') .getAll(applicationId, {index: 'applicationId'}) for (const category of categoriesList) { if(category.slug.length > 0) { categoryIds2SlugMap[category.id] = category.slug categoriesSlugsMap.set(category.slug, category) categoriesMap.set(category.id, category) } } for (const resource of channel.resources) { const categoryIds = [] const categorySlugs = resource.categorySlugs || [] const digitalAssetIds = [] const digitalAssetMap = {} // Convert slugs to ids if(categorySlugs.length > 0) { for (const slug of categorySlugs) { const category = categoriesSlugsMap.get(slug) if(category && category.id) { categoryIds.push(category.id) } } } const pkg = { applicationId, categoryIds, expand: false, ignoreDocumentIds, mode: [], order: resource.order || {by: 'publishedAt', dir: 'desc'}, status: ['published'], tags: resource.tags || [], taxonomyOperator: resource.taxonomyOperator || 'or', userId: '', title: '', } const order = pkg.order let query = r .table('documents') .getAll(applicationId, {index: 'applicationId'}) .filter(documentModel._getAllDocFilter(pkg)) if (options.rss) { query = query .eqJoin('activeRevisionId', r.table('document_revisions')) .map(function(doc) { return doc('left').merge({fields: doc('right')('fields')}) }) .eqJoin('userId', r.table('users')) .map(function(doc) { return doc('left').merge({user: doc('right')}) }) } query = query .orderBy(r[order.dir](order.by)) if (options.rss) { query = query.limit(30) } else if(resource.limit) { query = query.limit(resource.limit) } const res = await query.run() const docs = [] const docMap = new Map() for(let j = 0, k = res.length; j < k; j++) { const doc = res[j] doc.categories = [] ignoreDocumentIds.push(doc.id) if(doc.categoryIds && doc.categoryIds.length > 0) { for(let m = 0, n = doc.categoryIds.length; m < n; m++) { const categoryId = doc.categoryIds[m] doc.categories.push(categoriesMap.get(categoryId)) } } if(doc.featuredImageId) { digitalAssetIds.push(doc.featuredImageId) digitalAssetMap[doc.featuredImageId] = doc.id } doc.permalink = documentModel.generatePermalink2(doc) docMap.set(doc.id, doc) } if(digitalAssetIds.length > 0) { const daRes = await daModel.getAll(digitalAssetIds) for(let i = 0, l = daRes.length; i < l; i++) { const da = daRes[i] const docId = digitalAssetMap[da.id] const tDoc = docMap.get(docId) tDoc.featuredImage = da docMap.set(docId, tDoc) } } for(let [key, value] of docMap) { docs.push(value) } map.set(resource.name, docs) } resolve({ channel, resources: Array.from(map) }) } catch(e) { reject(e) } }) } /** * Get channels of a category slug * * @public * @constructor * @param {Object} options - Options */ async ofCategory(categorySlug) { const applicationId = this.applicationId const docs = await r .table('channels') .filter({ applicationId }) .filter(function(channel) { return channel('resources')('categorySlugs') .concatMap(function(x) { return x }) // flatten to return the top-level document .contains(categorySlug) }) return docs } /** * Get channels of a document * * @public * @constructor * @param {Object} options - Options */ async ofDocument(documentId) { const applicationId = this.applicationId const organizationId = this.organizationId const {DocumentModel} = require('paradigm-documents') // prevent circular dep const documentModel = new DocumentModel({ organizationId, applicationId, logger: this.logger }) const doc = await documentModel.getById(documentId) const categorySlugs = [] for (const category of doc.categories) { if (!(categorySlugs.includes(category.slug))) { categorySlugs.push(category.slug) } } const channels = [] for (const categorySlug of categorySlugs) { const categoryChannels = await this.ofCategory(categorySlug) for (const channel of categoryChannels) { if (channels.some((x) => { return x.id === channel.id })) { continue } channels.push(channel) } } return channels } getSingleResource(params = {}, query = {}, options = {}) { const applicationId = this.applicationId || options.applicationId const id = params.id const ignoreDocumentIds = (query.ignoreDocumentIds) ? ((query.ignoreDocumentIds instanceof Array) ? query.ignoreDocumentIds : query.ignoreDocumentIds.split(',')) : [] const organizationId = this.organizationId || options.organizationId const slug = params.slug const selectedResource = params.resource || false const page = (query.page) ? parseInt(query.page, 10) - 1 : 0 const daModel = new DigitalAssetModel({ applicationId, logger: this.logger, organizationId }) const {DocumentModel} = require('paradigm-documents') // prevent circular dep const documentModel = new DocumentModel({ applicationId, logger: this.logger, organizationId }) return new Promise( async (resolve, reject) => { try { let channel if(id) { channel = await this.getById(id) } else { channel = await this.getBySlug(slug, { applicationId, organizationId }) } if(!channel) { return reject(structureErrorCodes('CHANNEL_INVALID', { applicationId, id, organizationId, slug })) } if(!channel.resources) channel.resources = [] let map = new Map() const categoriesMap = new Map() const categoryIds2SlugMap = {} const categoriesSlugsMap = new Map() const categoriesList = await r .table('categories') .getAll(applicationId, {index: 'applicationId'}) for(let i = 0, l = categoriesList.length; i < l; i++) { const category = categoriesList[i] if(category.slug.length > 0) { categoryIds2SlugMap[category.id] = category.slug categoriesSlugsMap.set(category.slug, category) categoriesMap.set(category.id, category) } } for(let i = 0, l = channel.resources.length; i < l; i++) { const categoryIds = [] const resource = channel.resources[i] const categorySlugs = resource.categorySlugs || [] const digitalAssetIds = [] const digitalAssetMap = {} const limit = resource.limit || 0 // Convert slugs to ids if(categorySlugs.length > 0) { for(let j = 0, k = categorySlugs.length; j < k; j++) { const slug = categorySlugs[j] const category = categoriesSlugsMap.get(slug) if(category && category.id) { categoryIds.push(category.id) } } } let options = { applicationId, categoryIds, expand: false, ignoreDocumentIds, mode: [], order: resource.order || {by: 'publishedAt', dir: 'desc'}, status: ['published'], tags: resource.tags || [], taxonomyOperator: resource.taxonomyOperator || 'or', userId: '', title: '', } const order = options.order if(selectedResource && resource.name === selectedResource) { let query = r .table('documents') .getAll(applicationId, {index: 'applicationId'}) .filter(documentModel._getAllDocFilter(options)) .orderBy(r[order.dir](order.by)) if (limit) { const skipAmount = (limit * page) query = query .skip(skipAmount) .limit(limit) } const res = await query.run() const docs = [] const docMap = new Map() for(let j = 0, k = res.length; j < k; j++) { const doc = res[j] doc.categories = [] ignoreDocumentIds.push(doc.id) if(doc.categoryIds && doc.categoryIds.length > 0) { for(let m = 0, n = doc.categoryIds.length; m < n; m++) { const categoryId = doc.categoryIds[m] doc.categories.push(categoriesMap.get(categoryId)) } } if(doc.featuredImageId) { digitalAssetIds.push(doc.featuredImageId) digitalAssetMap[doc.featuredImageId] = doc.id } doc.permalink = documentModel.generatePermalink2(doc) docMap.set(doc.id, doc) } if(digitalAssetIds.length > 0) { const daRes = await daModel.getAll(digitalAssetIds) for(let i = 0, l = daRes.length; i < l; i++) { const da = daRes[i] const docId = digitalAssetMap[da.id] const tDoc = docMap.get(docId) tDoc.featuredImage = da docMap.set(docId, tDoc) } } for(let [key, value] of docMap) { docs.push(value) } map.set(selectedResource, docs) // Get just enough to get Id and length of other sources } else { let query = r .table('documents') .getAll(applicationId, {index: 'applicationId'}) .filter(documentModel._getAllDocFilter(options)) .pluck('id', 'publishedAt') .orderBy(r[order.dir](order.by)) if(resource.limit) { query = query.limit(resource.limit) } const res = await query.run() for(let j = 0, k = res.length; j < k; j++) { const doc = res[j] ignoreDocumentIds.push(doc.id) } } } resolve({ channel, resources: Array.from(map), //stats }) } catch(e) { reject(e) } }) } matchBySlug(slug, options = {}) { return this.getBySlug.apply(this, arguments) } } module.exports = ChannelModel