diff --git a/server/helpers/post.helper.js b/server/helpers/post.helper.js index 3a1e05be..2e560f0d 100644 --- a/server/helpers/post.helper.js +++ b/server/helpers/post.helper.js @@ -1,3 +1,4 @@ +import algoliasearch from 'algoliasearch'; import Like from '../models/like.model'; import Favorite from '../models/favorite.model'; import { getAdFreeMp3 } from '../helpers/mp3.helper'; @@ -8,6 +9,39 @@ function replaceWithAdFree(post, fullUser) { post.rss = getPrivateRss(fullUser) // eslint-disable-line } +async function getSearchQuery({ + search, topic, limit, createdAtBefore +}) { + const client = algoliasearch( + process.env.ALGOLIA_APP_ID, + process.env.ALGOLIA_API_KEY, + ); + + const index = client.initIndex(process.env.ALGOLIA_POSTS_INDEX); + const timestamp = new Date(createdAtBefore).getTime(); + const searchQuery = { + query: search, + filters: `date_timestamp < ${timestamp}`, + hitsPerPage: limit || 10, + }; + + if (topic) { + searchQuery.filters += ` AND topics:${topic}`; + } + + return new Promise((resolve, reject) => { + index.search(searchQuery) + .then((reply) => { + return resolve({ + slug: { + $in: reply.hits.map(h => h.slug), + }, + }); + }) + .catch(e => reject(e)); + }); +} + async function addPostData(post, fullUser) { const query = { userId: fullUser ? fullUser._id : null, @@ -43,13 +77,17 @@ async function getAdFreePostsIfSubscribed(posts, fullUser) { // Here we do this so we can // fetch subscriptions: const _posts = posts.map(async (post) => { - return await addPostData(post, fullUser); // eslint-disable-line + return await addPostData( // eslint-disable-line + typeof post.toObject === 'function' ? post.toObject() : post, + fullUser, + ); }); return Promise.all(_posts); } export { + getSearchQuery, replaceWithAdFree, addPostData, getAdFreePostsIfSubscribed, diff --git a/server/models/post.model.js b/server/models/post.model.js index 2f376042..13461aaa 100644 --- a/server/models/post.model.js +++ b/server/models/post.model.js @@ -4,6 +4,7 @@ import moment from 'moment'; import httpStatus from 'http-status'; import APIError from '../helpers/APIError'; import Vote from './vote.model'; +import { getSearchQuery } from './../helpers/post.helper'; import config from '../../config/config'; const slug = require('mongoose-slug-generator'); @@ -161,7 +162,7 @@ PostSchema.statics = { * @param {string} transcripts - Get posts with or without transcripts * @returns {Promise} */ - list({ + async list({ slugs = [], limit = 10, createdAtBefore = null, @@ -174,33 +175,42 @@ PostSchema.statics = { search = null, transcripts = null } = {}) { - const query = {}; + const limitOption = parseInt(limit, 10); + + let query = {}; + // @TODO use let numberOfPages = 0; //eslint-disable-line - let dateDirection = -1; - if (createdAtBefore) query.date = { $lt: moment(createdAtBefore).toDate() }; + + if (createdAtBefore) { + query.date = { + $lt: moment(createdAtBefore).toDate(), + }; + } + if (createdAfter) { dateDirection = 1; - query.date = { $gt: moment(createdAfter).toDate() }; + query.date = { + $gt: moment(createdAfter).toDate(), + }; } if (tags.length > 0) query.tags = { $all: tags }; if (categories.length > 0) query.categories = { $all: categories }; if (slugs.length > 0) query.slug = { $in: slugs }; if (topic) query.topics = { $in: topic }; - if (search) { - const titleSearch = {}; - const searchWords = search.split(' ').join('|'); - titleSearch['title.rendered'] = { - $regex: new RegExp(`${searchWords}`, 'i') - }; - - // @TODO: Add this when content doesn't have so much extra data - // let contentSearch = {} - // contentSearch['content.rendered'] = { $regex: new RegExp(`${search}`, 'i') }; - query.$or = [titleSearch]; + if (search) { + try { + query = await getSearchQuery({ + search, + limit, + createdAtBefore, + }); + } catch (err) { + console.error(err); //eslint-disable-line + } } if (transcripts === 'true') { @@ -209,8 +219,6 @@ PostSchema.statics = { query.transcriptUrl = { $exists: false }; } - const limitOption = parseInt(limit, 10); - let sort = { date: dateDirection }; if (type === 'top') { @@ -226,6 +234,7 @@ PostSchema.statics = { if (dateDirection === 1) { queryPromise.sort({ date: -1 }); } + if (!user) { return queryPromise.then(postsFound => postsFound); } @@ -235,10 +244,10 @@ PostSchema.statics = { select: 'active', match: { userId: user._id } }) - // .lean() // returns as plain object, but this will remove deafault values which is bad + // .lean() // returns as plain object, but this will remove deafault values which is bad .exec() .then((postsFound) => { - // add bookmarked + // add bookmarked const postsWithBookmarked = postsFound.map((post) => { const _post = post; const { bookmarkedByUser } = _post; @@ -246,6 +255,7 @@ PostSchema.statics = { delete _post.bookmarkedByUser; return Object.assign({}, post.toObject(), { bookmarked }); }); + // add vote info return this.addVotesForUserToPosts(postsWithBookmarked, user._id); });