diff --git a/src/dummy.js b/src/dummy.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/topics/suggested.js b/src/topics/suggested.js index bc8bbd2102..449ab6a196 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -1,79 +1,68 @@ - -'use strict'; - -const _ = require('lodash'); - -const db = require('../database'); -const user = require('../user'); -const privileges = require('../privileges'); -const plugins = require('../plugins'); - -module.exports = function (Topics) { - Topics.getSuggestedTopics = async function (tid, uid, start, stop, cutoff = 0) { - let tids; - if (!tid) { - return []; - } - tid = String(tid); - cutoff = cutoff === 0 ? cutoff : (cutoff * 2592000000); - const { cid, title, tags } = await Topics.getTopicFields(tid, [ - 'cid', 'title', 'tags', - ]); - - const [tagTids, searchTids] = await Promise.all([ - getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), - getSearchTids(tid, title, cid, cutoff), - ]); - - tids = _.uniq(tagTids.concat(searchTids)); - - let categoryTids = []; - if (stop !== -1 && tids.length < stop - start + 1) { - categoryTids = await getCategoryTids(tid, cid, cutoff); - } - tids = _.shuffle(_.uniq(tids.concat(categoryTids))); - tids = await privileges.topics.filterTids('topics:read', tids, uid); - - let topicData = await Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter(topic => topic && String(topic.tid) !== tid); - topicData = await user.blocks.filter(uid, topicData); - topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) - .sort((t1, t2) => t2.timestamp - t1.timestamp); - Topics.calculateTopicIndices(topicData, start); - return topicData; - }; - - async function getTidsWithSameTags(tid, tags, cutoff) { - let tids = cutoff === 0 ? - await db.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : - await db.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff); - tids = tids.filter(_tid => _tid !== tid); // remove self - return _.shuffle(_.uniq(tids)).slice(0, 10); - } - - async function getSearchTids(tid, title, cid, cutoff) { - let { ids: tids } = await plugins.hooks.fire('filter:search.query', { - index: 'topic', - content: title, - matchWords: 'any', - cid: [cid], - limit: 20, - ids: [], - }); - tids = tids.filter(_tid => String(_tid) !== tid); // remove self - if (cutoff) { - const topicData = await Topics.getTopicsFields(tids, ['tid', 'timestamp']); - const now = Date.now(); - tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); - } - - return _.shuffle(tids).slice(0, 10).map(String); - } - - async function getCategoryTids(tid, cid, cutoff) { - const tids = cutoff === 0 ? - await db.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) : - await db.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff); - return _.shuffle(tids.filter(_tid => _tid !== tid)); - } +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +const lodash_1 = __importDefault(require("lodash")); +const database_1 = __importDefault(require("../database")); +const user_1 = __importDefault(require("../user")); +const privileges_1 = __importDefault(require("../privileges")); +const plugins_1 = __importDefault(require("../plugins")); +function Suggested(Topics) { + async function getTidsWithSameTags(tid, tags, cutoff) { + const tids = cutoff === 0 ? + await (database_1.default === null || database_1.default === void 0 ? void 0 : database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1)) : + await (database_1.default === null || database_1.default === void 0 ? void 0 : database_1.default.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff)); + return lodash_1.default.shuffle(lodash_1.default.uniq((await tids).filter((_tid) => _tid !== tid))).slice(0, 10); + } + async function getSearchTids(tid, title, cid, cutoff, uid) { + const { ids: tids } = await plugins_1.default.hooks.fire('filter:search.query', { + index: 'topic', + content: title, + matchWords: 'any', + cid: [cid], + limit: 20, + ids: [], + }); + const filteredTids = tids.filter(_tid => _tid !== tid); + if (cutoff) { + const topicData = await Topics.getTopicsByTids(filteredTids, uid); + const now = Date.now(); + return lodash_1.default.shuffle(topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid)).slice(0, 10); + } + return lodash_1.default.shuffle(filteredTids).slice(0, 10); + } + async function getCategoryTids(tid, cid, cutoff) { + const tids = cutoff === 0 ? + await (database_1.default === null || database_1.default === void 0 ? void 0 : database_1.default.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9)) : + await (database_1.default === null || database_1.default === void 0 ? void 0 : database_1.default.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff)); + return lodash_1.default.shuffle((await tids).filter((_tid) => _tid !== tid)); + } + Topics.getSuggestedTopics = async function (tid, uid, start, stop, cutoff = 0) { + if (!tid) + return []; + tid = String(tid); + cutoff = cutoff === 0 ? cutoff : cutoff * 2592000000; + const { cid, title, tags } = await Topics.getTopicFields(tid, ['cid', 'title', 'tags']); + const [tagTids, searchTids] = await Promise.all([ + getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), + getSearchTids(tid, title, cid, cutoff, uid), + ]); + let tids = lodash_1.default.uniq([...tagTids, ...searchTids]); + let categoryTids = []; + if (stop !== -1 && (tids).length < stop - start + 1) { + categoryTids = await getCategoryTids(tid, cid, cutoff); + } + tids = lodash_1.default.shuffle(lodash_1.default.uniq([...tids, ...categoryTids])); + tids = await privileges_1.default.topics.filterTids('topics:read', tids, uid); + let topicData = await Topics.getTopicsByTids(tids, uid); + topicData = topicData.filter(topic => topic && topic.tid !== tid); + topicData = await user_1.default.blocks.filter(uid, topicData); + topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) + .sort((t1, t2) => t2.timestamp - t1.timestamp); + Topics.calculateTopicIndices(topicData, start); + return topicData; + }; +} +module.exports = Suggested; diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts new file mode 100644 index 0000000000..2bc031664c --- /dev/null +++ b/src/topics/suggested.ts @@ -0,0 +1,112 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import _ from 'lodash'; +import db from '../database'; +import user from '../user'; +import privileges from '../privileges'; +import plugins from '../plugins'; + +interface Topic { + tid: string; + timestamp: number; +} + +interface TopicFields { + cid: string; + title: string; + tags: { value: string }[]; +} + +interface TopicsType { + getTopicFields: (tid: string, fields: string[]) => Promise; + getTopicsByTids: (tids: string[], uid: string) => Promise; + calculateTopicIndices: (topics: Topic[], start: number) => void; + getSuggestedTopics?: ( + tid: string, + uid: string, + start: number, + stop: number, + cutoff?: number + ) => Promise; +} + +function Suggested(Topics: TopicsType) { + async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { + const tids = cutoff === 0 ? + await db?.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) as Promise : + await db?.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff) as Promise; + + return _.shuffle(_.uniq((await tids).filter((_tid: string) => _tid !== tid))).slice(0, 10); + } + + async function getSearchTids( + tid: string, title: string, cid: string, cutoff: number, uid: string + ): Promise { + const { ids: tids } = await plugins.hooks.fire('filter:search.query', { + index: 'topic', + content: title, + matchWords: 'any', + cid: [cid], + limit: 20, + ids: [], + }) as { ids: string[] }; + + const filteredTids = tids.filter(_tid => _tid !== tid); + + if (cutoff) { + const topicData = await Topics.getTopicsByTids(filteredTids, uid); + const now = Date.now(); + return _.shuffle( + topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid) + ).slice(0, 10); + } + + return _.shuffle(filteredTids).slice(0, 10); + } + + async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { + const tids = cutoff === 0 ? + await db?.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) as Promise : + await db?.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff) as Promise; + + return _.shuffle((await tids).filter((_tid: string) => _tid !== tid)); + } + + Topics.getSuggestedTopics = async function ( + tid: string, + uid: string, + start: number, + stop: number, + cutoff = 0 + ): Promise { + if (!tid) return []; + + tid = String(tid); + cutoff = cutoff === 0 ? cutoff : cutoff * 2592000000; + const { cid, title, tags } = await Topics.getTopicFields(tid, ['cid', 'title', 'tags']); + + const [tagTids, searchTids] = await Promise.all([ + getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), + getSearchTids(tid, title, cid, cutoff, uid), + ]); + + let tids = _.uniq([...tagTids, ...searchTids]); + + let categoryTids: string[] = []; + if (stop !== -1 && (tids).length < stop - start + 1) { + categoryTids = await getCategoryTids(tid, cid, cutoff); + } + tids = _.shuffle(_.uniq([...tids, ...categoryTids])); + tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; + + let topicData = await Topics.getTopicsByTids(tids, uid); + topicData = topicData.filter(topic => topic && topic.tid !== tid); + topicData = await user.blocks.filter(uid, topicData) as Topic[]; + topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) + .sort((t1, t2) => t2.timestamp - t1.timestamp); + Topics.calculateTopicIndices(topicData, start); + return topicData; + }; +} + +export = Suggested diff --git a/tsconfig.json b/tsconfig.json index 10aeeef7e6..c15cb37711 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "allowJs": false, - "target": "es6", + "target": "es2017", "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true,