From db80df9efdcc297795b8108ff86fdf67d3b2504e Mon Sep 17 00:00:00 2001 From: sterlingrules Date: Tue, 10 Mar 2020 19:52:48 -0400 Subject: [PATCH 1/3] fix(): search endpoint for mobile --- server/controllers/post.controller.js | 2 +- server/helpers/post.helper.js | 29 ++++++++++++++++ server/models/post.model.js | 50 ++++++++++++++++----------- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/server/controllers/post.controller.js b/server/controllers/post.controller.js index 33692e49..4ecd19a4 100644 --- a/server/controllers/post.controller.js +++ b/server/controllers/post.controller.js @@ -121,7 +121,7 @@ async function get(req, res, next) { * $ref: '#/definitions/Post' */ -function list(req, res, next) { +async function list(req, res, next) { const { limit = null, createdAtBefore = null, diff --git a/server/helpers/post.helper.js b/server/helpers/post.helper.js index 3a1e05be..3292979d 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,33 @@ function replaceWithAdFree(post, fullUser) { post.rss = getPrivateRss(fullUser) // eslint-disable-line } +async function getSearchQuery({ search, 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, + }; + + 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, @@ -50,6 +78,7 @@ async function getAdFreePostsIfSubscribed(posts, fullUser) { } 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); }); From ab72eb48cf22f9c7c01e26e486103b0af33cc156 Mon Sep 17 00:00:00 2001 From: sterlingrules Date: Tue, 10 Mar 2020 21:29:49 -0400 Subject: [PATCH 2/3] feat(): add topic search support, fix search props --- server/helpers/post.helper.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server/helpers/post.helper.js b/server/helpers/post.helper.js index 3292979d..2e560f0d 100644 --- a/server/helpers/post.helper.js +++ b/server/helpers/post.helper.js @@ -9,7 +9,9 @@ function replaceWithAdFree(post, fullUser) { post.rss = getPrivateRss(fullUser) // eslint-disable-line } -async function getSearchQuery({ search, limit, createdAtBefore }) { +async function getSearchQuery({ + search, topic, limit, createdAtBefore +}) { const client = algoliasearch( process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_API_KEY, @@ -23,6 +25,10 @@ async function getSearchQuery({ search, limit, createdAtBefore }) { hitsPerPage: limit || 10, }; + if (topic) { + searchQuery.filters += ` AND topics:${topic}`; + } + return new Promise((resolve, reject) => { index.search(searchQuery) .then((reply) => { @@ -71,7 +77,10 @@ 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); From 75fd67b3bb8af82fe4f9c30038abe91858b0926c Mon Sep 17 00:00:00 2001 From: sterlingrules Date: Tue, 10 Mar 2020 21:46:11 -0400 Subject: [PATCH 3/3] chore(): code cleanup --- server/controllers/post.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/controllers/post.controller.js b/server/controllers/post.controller.js index 4ecd19a4..33692e49 100644 --- a/server/controllers/post.controller.js +++ b/server/controllers/post.controller.js @@ -121,7 +121,7 @@ async function get(req, res, next) { * $ref: '#/definitions/Post' */ -async function list(req, res, next) { +function list(req, res, next) { const { limit = null, createdAtBefore = null,