From 48c56134b099e82751595e0d4702735ccdc7b82c Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Sun, 13 Oct 2024 14:30:18 -0400 Subject: [PATCH 01/13] "Refactor suggested topics function to use async/await syntax and update imports to use default imports" --- src/dummy.js | 0 src/topics/suggested.js | 161 +++++++++++++++++++++------------------- src/topics/suggested.ts | 88 ++++++++++++++++++++++ 3 files changed, 173 insertions(+), 76 deletions(-) create mode 100644 src/dummy.js create mode 100644 src/topics/suggested.ts 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..0164c92879 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -1,79 +1,88 @@ - 'use strict'; - -const _ = require('lodash'); - -const db = require('../database'); -const user = require('../user'); -const privileges = require('../privileges'); -const plugins = require('../plugins'); - +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +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")); 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)); - } + Topics.getSuggestedTopics = function (tid_1, uid_1, start_1, stop_1) { + return __awaiter(this, arguments, void 0, 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 } = yield Topics.getTopicFields(tid, [ + 'cid', 'title', 'tags', + ]); + const [tagTids, searchTids] = yield Promise.all([ + getTidsWithSameTags(tid, tags.map((t) => t.value), cutoff), + getSearchTids(tid, title, cid, cutoff), + ]); + tids = lodash_1.default.uniq(tagTids.concat(searchTids)); + let categoryTids = []; + if (stop !== -1 && tids.length < stop - start + 1) { + categoryTids = yield getCategoryTids(tid, cid, cutoff); + } + tids = lodash_1.default.shuffle(lodash_1.default.uniq(tids.concat(categoryTids))); + tids = yield privileges_1.default.topics.filterTids('topics:read', tids, uid); + let topicData = yield Topics.getTopicsByTids(tids, uid); + topicData = topicData.filter((topic) => topic && String(topic.tid) !== tid); + topicData = yield 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; + }); + }; + function getTidsWithSameTags(tid, tags, cutoff) { + return __awaiter(this, void 0, void 0, function* () { + let tids = cutoff === 0 ? + yield database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : + yield database_1.default.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff); + tids = tids.filter((_tid) => _tid !== tid); // remove self + return lodash_1.default.shuffle(lodash_1.default.uniq(tids)).slice(0, 10); + }); + } + function getSearchTids(tid, title, cid, cutoff) { + return __awaiter(this, void 0, void 0, function* () { + let { ids: tids } = yield plugins_1.default.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 = yield Topics.getTopicsFields(tids, ['tid', 'timestamp']); + const now = Date.now(); + tids = topicData.filter((t) => t && t.timestamp > now - cutoff).map((t) => t.tid); + } + return lodash_1.default.shuffle(tids).slice(0, 10).map(String); + }); + } + function getCategoryTids(tid, cid, cutoff) { + return __awaiter(this, void 0, void 0, function* () { + const tids = cutoff === 0 ? + yield database_1.default.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) : + yield database_1.default.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff); + return lodash_1.default.shuffle(tids.filter((_tid) => _tid !== tid)); + }); + } }; diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts new file mode 100644 index 0000000000..864ac5eb01 --- /dev/null +++ b/src/topics/suggested.ts @@ -0,0 +1,88 @@ +'use strict'; + +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; +} + +module.exports = function (Topics: any) { + Topics.getSuggestedTopics = async function ( + tid: string, + uid: string, + start: number, + stop: number, + cutoff: number = 0 + ): Promise { + let tids: string[] = []; + 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: any) => t.value), cutoff), + getSearchTids(tid, title, cid, cutoff), + ]); + + tids = _.uniq(tagTids.concat(searchTids)); + + let categoryTids: string[] = []; + 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: any) => topic && String(topic.tid) !== tid); + topicData = await user.blocks.filter(uid, topicData); + topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) + .sort((t1: Topic, t2: Topic) => t2.timestamp - t1.timestamp); + Topics.calculateTopicIndices(topicData, start); + return topicData; + }; + + async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { + 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: string) => _tid !== tid); // remove self + return _.shuffle(_.uniq(tids)).slice(0, 10); + } + + async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { + 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) => String(_tid) !== tid); // remove self + if (cutoff) { + const topicData = await Topics.getTopicsFields(tids, ['tid', 'timestamp']); + const now = Date.now(); + tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); + } + + return _.shuffle(tids).slice(0, 10).map(String); + } + + async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { + 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: string) => _tid !== tid)); + } +}; From 0136d883ba2cf816aef68d907c7b8e39540efee7 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Sun, 13 Oct 2024 14:53:53 -0400 Subject: [PATCH 02/13] "Refactor suggested topics module to use ES6 syntax and move functions inside Suggested function" --- src/topics/suggested.js | 71 +++++++++++++++++----------------- src/topics/suggested.ts | 84 ++++++++++++++++++++--------------------- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 0164c92879..eb4824ef68 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -12,43 +12,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = Suggested; +// La siguiente línea llama a una función en un módulo que aún no ha sido actualizado a TS +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @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")); -module.exports = function (Topics) { - Topics.getSuggestedTopics = function (tid_1, uid_1, start_1, stop_1) { - return __awaiter(this, arguments, void 0, 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 } = yield Topics.getTopicFields(tid, [ - 'cid', 'title', 'tags', - ]); - const [tagTids, searchTids] = yield Promise.all([ - getTidsWithSameTags(tid, tags.map((t) => t.value), cutoff), - getSearchTids(tid, title, cid, cutoff), - ]); - tids = lodash_1.default.uniq(tagTids.concat(searchTids)); - let categoryTids = []; - if (stop !== -1 && tids.length < stop - start + 1) { - categoryTids = yield getCategoryTids(tid, cid, cutoff); - } - tids = lodash_1.default.shuffle(lodash_1.default.uniq(tids.concat(categoryTids))); - tids = yield privileges_1.default.topics.filterTids('topics:read', tids, uid); - let topicData = yield Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter((topic) => topic && String(topic.tid) !== tid); - topicData = yield 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; - }); - }; +function Suggested(Topics) { function getTidsWithSameTags(tid, tags, cutoff) { return __awaiter(this, void 0, void 0, function* () { let tids = cutoff === 0 ? @@ -85,4 +57,35 @@ module.exports = function (Topics) { return lodash_1.default.shuffle(tids.filter((_tid) => _tid !== tid)); }); } -}; + Topics.getSuggestedTopics = function (tid_1, uid_1, start_1, stop_1) { + return __awaiter(this, arguments, void 0, 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 } = yield Topics.getTopicFields(tid, [ + 'cid', 'title', 'tags', + ]); + const [tagTids, searchTids] = yield Promise.all([ + getTidsWithSameTags(tid, tags.map((t) => t.value), cutoff), + getSearchTids(tid, title, cid, cutoff), + ]); + tids = lodash_1.default.uniq(tagTids.concat(searchTids)); + let categoryTids = []; + if (stop !== -1 && tids.length < stop - start + 1) { + categoryTids = yield getCategoryTids(tid, cid, cutoff); + } + tids = lodash_1.default.shuffle(lodash_1.default.uniq(tids.concat(categoryTids))); + tids = yield privileges_1.default.topics.filterTids('topics:read', tids, uid); + let topicData = yield Topics.getTopicsByTids(tids, uid); + topicData = topicData.filter((topic) => topic && String(topic.tid) !== tid); + topicData = yield 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; + }); + }; +} diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 864ac5eb01..7205a79cb7 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -1,5 +1,5 @@ -'use strict'; - +// La siguiente línea llama a una función en un módulo que aún no ha sido actualizado a TS +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call import _ from 'lodash'; import db from '../database'; import user from '../user'; @@ -11,12 +11,46 @@ interface Topic { timestamp: number; } -module.exports = function (Topics: any) { +export default function Suggested(Topics: any) { + async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { + 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: string) => _tid !== tid); // remove self + return _.shuffle(_.uniq(tids)).slice(0, 10); + } + + async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { + 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) => String(_tid) !== tid); // remove self + if (cutoff) { + const topicData = await Topics.getTopicsFields(tids, ['tid', 'timestamp']); + const now = Date.now(); + tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); + } + + return _.shuffle(tids).slice(0, 10).map(String); + } + + async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { + 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: string) => _tid !== tid)); + } + Topics.getSuggestedTopics = async function ( - tid: string, - uid: string, - start: number, - stop: number, + tid: string, + uid: string, + start: number, + stop: number, cutoff: number = 0 ): Promise { let tids: string[] = []; @@ -51,38 +85,4 @@ module.exports = function (Topics: any) { Topics.calculateTopicIndices(topicData, start); return topicData; }; - - async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { - 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: string) => _tid !== tid); // remove self - return _.shuffle(_.uniq(tids)).slice(0, 10); - } - - async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { - 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) => String(_tid) !== tid); // remove self - if (cutoff) { - const topicData = await Topics.getTopicsFields(tids, ['tid', 'timestamp']); - const now = Date.now(); - tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); - } - - return _.shuffle(tids).slice(0, 10).map(String); - } - - async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { - 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: string) => _tid !== tid)); - } -}; +} From 4c83056e5a9bff0edc2004e2c00a1bb6932639f2 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Sun, 13 Oct 2024 15:06:56 -0400 Subject: [PATCH 03/13] Remove unnecessary comment and ESLint disable lines in suggested.ts --- src/topics/suggested.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 7205a79cb7..4e0bc0c778 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -1,5 +1,3 @@ -// La siguiente línea llama a una función en un módulo que aún no ha sido actualizado a TS -// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call import _ from 'lodash'; import db from '../database'; import user from '../user'; From 44198d92ecc7775cf1e30e971d03d0674aaad504 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 00:15:07 -0400 Subject: [PATCH 04/13] "Updated suggested topics function to fix type issues and add type annotations" --- src/topics/suggested.js | 14 +++++++----- src/topics/suggested.ts | 48 +++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index eb4824ef68..c2dd2b5565 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -13,8 +13,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Suggested; -// La siguiente línea llama a una función en un módulo que aún no ha sido actualizado a TS -// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* 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")); @@ -26,7 +28,8 @@ function Suggested(Topics) { let tids = cutoff === 0 ? yield database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : yield database_1.default.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff); - tids = tids.filter((_tid) => _tid !== tid); // remove self + // Solución: Filtrar solo si el tipo de _tid es válido + tids = tids.filter((_tid) => typeof _tid === 'string' && _tid !== tid); return lodash_1.default.shuffle(lodash_1.default.uniq(tids)).slice(0, 10); }); } @@ -38,11 +41,12 @@ function Suggested(Topics) { matchWords: 'any', cid: [cid], limit: 20, - ids: [], + ids: [], // especificamos el tipo }); tids = tids.filter((_tid) => String(_tid) !== tid); // remove self if (cutoff) { - const topicData = yield Topics.getTopicsFields(tids, ['tid', 'timestamp']); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const topicData = yield Topics.getTopicsByTids(tids, ['tid', 'timestamp']); const now = Date.now(); tids = topicData.filter((t) => t && t.timestamp > now - cutoff).map((t) => t.tid); } diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 4e0bc0c778..976b626d49 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -1,3 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* 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'; @@ -5,16 +9,37 @@ import privileges from '../privileges'; import plugins from '../plugins'; interface Topic { - tid: string; - timestamp: number; + tid: string; + timestamp: number; } -export default function Suggested(Topics: any) { - async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { - let tids = cutoff === 0 ? +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; +} + +export default function Suggested(Topics: TopicsType) { + async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { + let tids: string[] = 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: string) => _tid !== tid); // remove self + + // Solución: Filtrar solo si el tipo de _tid es válido + tids = tids.filter((_tid: string) => typeof _tid === 'string' && _tid !== tid); return _.shuffle(_.uniq(tids)).slice(0, 10); } @@ -25,11 +50,12 @@ export default function Suggested(Topics: any) { matchWords: 'any', cid: [cid], limit: 20, - ids: [], + ids: [] as string[], // especificamos el tipo }); tids = tids.filter((_tid: string) => String(_tid) !== tid); // remove self if (cutoff) { - const topicData = await Topics.getTopicsFields(tids, ['tid', 'timestamp']); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const topicData = await Topics.getTopicsByTids(tids, ['tid', 'timestamp']); const now = Date.now(); tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); } @@ -46,7 +72,7 @@ export default function Suggested(Topics: any) { Topics.getSuggestedTopics = async function ( tid: string, - uid: string, + uid: string[], start: number, stop: number, cutoff: number = 0 @@ -62,7 +88,7 @@ export default function Suggested(Topics: any) { ]); const [tagTids, searchTids] = await Promise.all([ - getTidsWithSameTags(tid, tags.map((t: any) => t.value), cutoff), + getTidsWithSameTags(tid, tags.map((t: { value: string }) => t.value), cutoff), getSearchTids(tid, title, cid, cutoff), ]); @@ -76,7 +102,7 @@ export default function Suggested(Topics: any) { tids = await privileges.topics.filterTids('topics:read', tids, uid); let topicData = await Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter((topic: any) => topic && String(topic.tid) !== tid); + topicData = topicData.filter((topic: Topic) => topic && String(topic.tid) !== tid); topicData = await user.blocks.filter(uid, topicData); topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) .sort((t1: Topic, t2: Topic) => t2.timestamp - t1.timestamp); From 214518bb514f8b6682cea9e50a56ea8edd4a8614 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 00:38:41 -0400 Subject: [PATCH 05/13] "Removed eslint-disable comments, added type annotations, and updated function implementations in suggested.js and suggested.ts files." --- src/topics/suggested.js | 12 ++++-------- src/topics/suggested.ts | 32 ++++++++++++++------------------ 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index c2dd2b5565..9ef3988153 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -13,8 +13,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Suggested; -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ const lodash_1 = __importDefault(require("lodash")); @@ -28,7 +26,6 @@ function Suggested(Topics) { let tids = cutoff === 0 ? yield database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : yield database_1.default.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff); - // Solución: Filtrar solo si el tipo de _tid es válido tids = tids.filter((_tid) => typeof _tid === 'string' && _tid !== tid); return lodash_1.default.shuffle(lodash_1.default.uniq(tids)).slice(0, 10); }); @@ -41,11 +38,10 @@ function Suggested(Topics) { matchWords: 'any', cid: [cid], limit: 20, - ids: [], // especificamos el tipo + ids: [], }); - tids = tids.filter((_tid) => String(_tid) !== tid); // remove self + tids = tids.filter((_tid) => String(_tid) !== tid); if (cutoff) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const topicData = yield Topics.getTopicsByTids(tids, ['tid', 'timestamp']); const now = Date.now(); tids = topicData.filter((t) => t && t.timestamp > now - cutoff).map((t) => t.tid); @@ -82,10 +78,10 @@ function Suggested(Topics) { categoryTids = yield getCategoryTids(tid, cid, cutoff); } tids = lodash_1.default.shuffle(lodash_1.default.uniq(tids.concat(categoryTids))); - tids = yield privileges_1.default.topics.filterTids('topics:read', tids, uid); + tids = (yield privileges_1.default.topics.filterTids('topics:read', tids, uid)); let topicData = yield Topics.getTopicsByTids(tids, uid); topicData = topicData.filter((topic) => topic && String(topic.tid) !== tid); - topicData = yield user_1.default.blocks.filter(uid, topicData); + topicData = (yield 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); diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 976b626d49..b7900e38ed 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ import _ from 'lodash'; @@ -35,12 +33,11 @@ interface TopicsType { export default function Suggested(Topics: TopicsType) { async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { let tids: string[] = 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); + await db.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) as string[] : + await db.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff) as string[]; - // Solución: Filtrar solo si el tipo de _tid es válido tids = tids.filter((_tid: string) => typeof _tid === 'string' && _tid !== tid); - return _.shuffle(_.uniq(tids)).slice(0, 10); + return _.shuffle(_.uniq(tids)).slice(0, 10) as string[]; } async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { @@ -50,24 +47,23 @@ export default function Suggested(Topics: TopicsType) { matchWords: 'any', cid: [cid], limit: 20, - ids: [] as string[], // especificamos el tipo - }); - tids = tids.filter((_tid: string) => String(_tid) !== tid); // remove self + ids: [] as string[], + }) as { ids: string[] }; + tids = tids.filter((_tid: string) => String(_tid) !== tid); if (cutoff) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const topicData = await Topics.getTopicsByTids(tids, ['tid', 'timestamp']); const now = Date.now(); tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); } - return _.shuffle(tids).slice(0, 10).map(String); + return _.shuffle(tids).slice(0, 10).map(String) as string[]; } async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { 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: string) => _tid !== tid)); + await db.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) as string[] : + await db.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff) as string[]; + return _.shuffle(tids.filter((_tid: string) => _tid !== tid)) as string[]; } Topics.getSuggestedTopics = async function ( @@ -92,18 +88,18 @@ export default function Suggested(Topics: TopicsType) { getSearchTids(tid, title, cid, cutoff), ]); - tids = _.uniq(tagTids.concat(searchTids)); + tids = _.uniq(tagTids.concat(searchTids)) as string[]; let categoryTids: string[] = []; 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); + tids = _.shuffle(_.uniq(tids.concat(categoryTids))) as string[]; + tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; let topicData = await Topics.getTopicsByTids(tids, uid); topicData = topicData.filter((topic: Topic) => topic && String(topic.tid) !== tid); - topicData = await user.blocks.filter(uid, topicData); + topicData = await user.blocks.filter(uid, topicData) as Topic[]; topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) .sort((t1: Topic, t2: Topic) => t2.timestamp - t1.timestamp); Topics.calculateTopicIndices(topicData, start); From fc493f05205e9f6c5b9e425e768d0bef2faa3178 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 01:08:50 -0400 Subject: [PATCH 06/13] "Refactor SuggestedTopics function: simplify variable declarations, remove unnecessary type checks, and update function calls" --- src/topics/suggested.js | 31 ++++++++++++---------------- src/topics/suggested.ts | 45 +++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 9ef3988153..4c4611ca48 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -23,11 +23,10 @@ const plugins_1 = __importDefault(require("../plugins")); function Suggested(Topics) { function getTidsWithSameTags(tid, tags, cutoff) { return __awaiter(this, void 0, void 0, function* () { - let tids = cutoff === 0 ? + const tids = cutoff === 0 ? yield database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : yield database_1.default.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff); - tids = tids.filter((_tid) => typeof _tid === 'string' && _tid !== tid); - return lodash_1.default.shuffle(lodash_1.default.uniq(tids)).slice(0, 10); + return lodash_1.default.shuffle(lodash_1.default.uniq(tids.filter(_tid => _tid !== tid))).slice(0, 10); }); } function getSearchTids(tid, title, cid, cutoff) { @@ -40,13 +39,13 @@ function Suggested(Topics) { limit: 20, ids: [], }); - tids = tids.filter((_tid) => String(_tid) !== tid); + tids = tids.filter(_tid => _tid !== tid); if (cutoff) { - const topicData = yield Topics.getTopicsByTids(tids, ['tid', 'timestamp']); + const topicData = yield Topics.getTopicsByTids(tids, ''); const now = Date.now(); - tids = topicData.filter((t) => t && t.timestamp > now - cutoff).map((t) => t.tid); + tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); } - return lodash_1.default.shuffle(tids).slice(0, 10).map(String); + return lodash_1.default.shuffle(tids).slice(0, 10); }); } function getCategoryTids(tid, cid, cutoff) { @@ -54,33 +53,29 @@ function Suggested(Topics) { const tids = cutoff === 0 ? yield database_1.default.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) : yield database_1.default.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff); - return lodash_1.default.shuffle(tids.filter((_tid) => _tid !== tid)); + return lodash_1.default.shuffle(tids.filter(_tid => _tid !== tid)); }); } Topics.getSuggestedTopics = function (tid_1, uid_1, start_1, stop_1) { return __awaiter(this, arguments, void 0, function* (tid, uid, start, stop, cutoff = 0) { - let tids = []; - if (!tid) { + if (!tid) return []; - } tid = String(tid); cutoff = cutoff === 0 ? cutoff : (cutoff * 2592000000); - const { cid, title, tags } = yield Topics.getTopicFields(tid, [ - 'cid', 'title', 'tags', - ]); + const { cid, title, tags } = yield Topics.getTopicFields(tid, ['cid', 'title', 'tags']); const [tagTids, searchTids] = yield Promise.all([ - getTidsWithSameTags(tid, tags.map((t) => t.value), cutoff), + getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), getSearchTids(tid, title, cid, cutoff), ]); - tids = lodash_1.default.uniq(tagTids.concat(searchTids)); + let tids = lodash_1.default.uniq([...tagTids, ...searchTids]); let categoryTids = []; if (stop !== -1 && tids.length < stop - start + 1) { categoryTids = yield getCategoryTids(tid, cid, cutoff); } - tids = lodash_1.default.shuffle(lodash_1.default.uniq(tids.concat(categoryTids))); + tids = lodash_1.default.shuffle(lodash_1.default.uniq([...tids, ...categoryTids])); tids = (yield privileges_1.default.topics.filterTids('topics:read', tids, uid)); let topicData = yield Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter((topic) => topic && String(topic.tid) !== tid); + topicData = topicData.filter(topic => topic && topic.tid !== tid); topicData = (yield user_1.default.blocks.filter(uid, topicData)); topicData = topicData.slice(start, stop !== -1 ? stop + 1 : undefined) .sort((t1, t2) => t2.timestamp - t1.timestamp); diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index b7900e38ed..5b2a1cf047 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -19,11 +19,11 @@ interface TopicFields { interface TopicsType { getTopicFields: (tid: string, fields: string[]) => Promise; - getTopicsByTids: (tids: string[], uid: string[]) => Promise; + getTopicsByTids: (tids: string[], uid: string) => Promise; calculateTopicIndices: (topics: Topic[], start: number) => void; getSuggestedTopics?: ( tid: string, - uid: string[], + uid: string, start: number, stop: number, cutoff?: number @@ -32,12 +32,11 @@ interface TopicsType { export default function Suggested(Topics: TopicsType) { async function getTidsWithSameTags(tid: string, tags: string[], cutoff: number): Promise { - let tids: string[] = cutoff === 0 ? + const tids = cutoff === 0 ? await db.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) as string[] : await db.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff) as string[]; - tids = tids.filter((_tid: string) => typeof _tid === 'string' && _tid !== tid); - return _.shuffle(_.uniq(tids)).slice(0, 10) as string[]; + return _.shuffle(_.uniq(tids.filter(_tid => _tid !== tid))).slice(0, 10) as string[]; } async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { @@ -47,61 +46,59 @@ export default function Suggested(Topics: TopicsType) { matchWords: 'any', cid: [cid], limit: 20, - ids: [] as string[], + ids: [], }) as { ids: string[] }; - tids = tids.filter((_tid: string) => String(_tid) !== tid); + + tids = tids.filter(_tid => _tid !== tid); if (cutoff) { - const topicData = await Topics.getTopicsByTids(tids, ['tid', 'timestamp']); + const topicData = await Topics.getTopicsByTids(tids, ''); const now = Date.now(); - tids = topicData.filter((t: Topic) => t && t.timestamp > now - cutoff).map((t: Topic) => t.tid); + tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); } - return _.shuffle(tids).slice(0, 10).map(String) as string[]; + return _.shuffle(tids).slice(0, 10) as string[]; } async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { const tids = cutoff === 0 ? await db.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) as string[] : await db.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff) as string[]; - return _.shuffle(tids.filter((_tid: string) => _tid !== tid)) as string[]; + + return _.shuffle(tids.filter(_tid => _tid !== tid)) as string[]; } Topics.getSuggestedTopics = async function ( tid: string, - uid: string[], + uid: string, start: number, stop: number, cutoff: number = 0 ): Promise { - let tids: string[] = []; - if (!tid) { - return []; - } + if (!tid) return []; + tid = String(tid); cutoff = cutoff === 0 ? cutoff : (cutoff * 2592000000); - const { cid, title, tags } = await Topics.getTopicFields(tid, [ - 'cid', 'title', 'tags', - ]); + const { cid, title, tags } = await Topics.getTopicFields(tid, ['cid', 'title', 'tags']); const [tagTids, searchTids] = await Promise.all([ - getTidsWithSameTags(tid, tags.map((t: { value: string }) => t.value), cutoff), + getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), getSearchTids(tid, title, cid, cutoff), ]); - tids = _.uniq(tagTids.concat(searchTids)) as string[]; + let tids = _.uniq([...tagTids, ...searchTids]) as string[]; let categoryTids: string[] = []; if (stop !== -1 && tids.length < stop - start + 1) { categoryTids = await getCategoryTids(tid, cid, cutoff); } - tids = _.shuffle(_.uniq(tids.concat(categoryTids))) as string[]; + tids = _.shuffle(_.uniq([...tids, ...categoryTids])) as string[]; tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; let topicData = await Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter((topic: Topic) => topic && String(topic.tid) !== tid); + 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: Topic, t2: Topic) => t2.timestamp - t1.timestamp); + .sort((t1, t2) => t2.timestamp - t1.timestamp); Topics.calculateTopicIndices(topicData, start); return topicData; }; From 5af78bfa5506c0650eb137a35dd0d2fdeb49ae60 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 01:16:55 -0400 Subject: [PATCH 07/13] Added `uid` parameter to `getSearchTids` function in `suggested.js` and `suggested.ts` files. --- src/topics/suggested.js | 6 +++--- src/topics/suggested.ts | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 4c4611ca48..120b61ff81 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -29,7 +29,7 @@ function Suggested(Topics) { return lodash_1.default.shuffle(lodash_1.default.uniq(tids.filter(_tid => _tid !== tid))).slice(0, 10); }); } - function getSearchTids(tid, title, cid, cutoff) { + function getSearchTids(tid, title, cid, cutoff, uid) { return __awaiter(this, void 0, void 0, function* () { let { ids: tids } = yield plugins_1.default.hooks.fire('filter:search.query', { index: 'topic', @@ -41,7 +41,7 @@ function Suggested(Topics) { }); tids = tids.filter(_tid => _tid !== tid); if (cutoff) { - const topicData = yield Topics.getTopicsByTids(tids, ''); + const topicData = yield Topics.getTopicsByTids(tids, uid); const now = Date.now(); tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); } @@ -65,7 +65,7 @@ function Suggested(Topics) { const { cid, title, tags } = yield Topics.getTopicFields(tid, ['cid', 'title', 'tags']); const [tagTids, searchTids] = yield Promise.all([ getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), - getSearchTids(tid, title, cid, cutoff), + getSearchTids(tid, title, cid, cutoff, uid), ]); let tids = lodash_1.default.uniq([...tagTids, ...searchTids]); let categoryTids = []; diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 5b2a1cf047..fc5ea2e926 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -39,7 +39,10 @@ export default function Suggested(Topics: TopicsType) { return _.shuffle(_.uniq(tids.filter(_tid => _tid !== tid))).slice(0, 10) as string[]; } - async function getSearchTids(tid: string, title: string, cid: string, cutoff: number): Promise { + async function getSearchTids( + tid: string, title: string, cid: string, cutoff: number, + uid: string + ): Promise { let { ids: tids } = await plugins.hooks.fire('filter:search.query', { index: 'topic', content: title, @@ -51,7 +54,7 @@ export default function Suggested(Topics: TopicsType) { tids = tids.filter(_tid => _tid !== tid); if (cutoff) { - const topicData = await Topics.getTopicsByTids(tids, ''); + const topicData = await Topics.getTopicsByTids(tids, uid); const now = Date.now(); tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); } @@ -82,7 +85,7 @@ export default function Suggested(Topics: TopicsType) { const [tagTids, searchTids] = await Promise.all([ getTidsWithSameTags(tid, tags.map(t => t.value), cutoff), - getSearchTids(tid, title, cid, cutoff), + getSearchTids(tid, title, cid, cutoff, uid), ]); let tids = _.uniq([...tagTids, ...searchTids]) as string[]; From e05134da2593048aa7f6810a4b4fde7d15871bd7 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 01:26:08 -0400 Subject: [PATCH 08/13] "Deleted file src/dummy.js" --- src/dummy.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/dummy.js diff --git a/src/dummy.js b/src/dummy.js deleted file mode 100644 index e69de29bb2..0000000000 From 60347889257ab219b81024ed1e3b48db590952f6 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 02:31:37 -0400 Subject: [PATCH 09/13] "Refactor suggested topics code to use async/await and update TypeScript configuration" --- src/dummy.js | 0 src/topics/suggested.js | 115 +++++++++++++++++----------------------- src/topics/suggested.ts | 40 +++++++------- tsconfig.json | 2 +- 4 files changed, 71 insertions(+), 86 deletions(-) create mode 100644 src/dummy.js 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 120b61ff81..e89edfad05 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -1,13 +1,4 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -21,66 +12,58 @@ const user_1 = __importDefault(require("../user")); const privileges_1 = __importDefault(require("../privileges")); const plugins_1 = __importDefault(require("../plugins")); function Suggested(Topics) { - function getTidsWithSameTags(tid, tags, cutoff) { - return __awaiter(this, void 0, void 0, function* () { - const tids = cutoff === 0 ? - yield database_1.default.getSortedSetRevRange(tags.map(tag => `tag:${tag}:topics`), 0, -1) : - yield 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(tids.filter(_tid => _tid !== tid))).slice(0, 10); - }); + 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); } - function getSearchTids(tid, title, cid, cutoff, uid) { - return __awaiter(this, void 0, void 0, function* () { - let { ids: tids } = yield plugins_1.default.hooks.fire('filter:search.query', { - index: 'topic', - content: title, - matchWords: 'any', - cid: [cid], - limit: 20, - ids: [], - }); - tids = tids.filter(_tid => _tid !== tid); - if (cutoff) { - const topicData = yield Topics.getTopicsByTids(tids, uid); - const now = Date.now(); - tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); - } - return lodash_1.default.shuffle(tids).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); } - function getCategoryTids(tid, cid, cutoff) { - return __awaiter(this, void 0, void 0, function* () { - const tids = cutoff === 0 ? - yield database_1.default.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) : - yield database_1.default.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff); - return lodash_1.default.shuffle(tids.filter(_tid => _tid !== tid)); - }); + 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 = function (tid_1, uid_1, start_1, stop_1) { - return __awaiter(this, arguments, void 0, function* (tid, uid, start, stop, cutoff = 0) { - if (!tid) - return []; - tid = String(tid); - cutoff = cutoff === 0 ? cutoff : (cutoff * 2592000000); - const { cid, title, tags } = yield Topics.getTopicFields(tid, ['cid', 'title', 'tags']); - const [tagTids, searchTids] = yield 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 = yield getCategoryTids(tid, cid, cutoff); - } - tids = lodash_1.default.shuffle(lodash_1.default.uniq([...tids, ...categoryTids])); - tids = (yield privileges_1.default.topics.filterTids('topics:read', tids, uid)); - let topicData = yield Topics.getTopicsByTids(tids, uid); - topicData = topicData.filter(topic => topic && topic.tid !== tid); - topicData = (yield 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; - }); + 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 && (await tids).length < stop - start + 1) { + categoryTids = await getCategoryTids(tid, cid, cutoff); + } + tids = lodash_1.default.shuffle(lodash_1.default.uniq([...await tids, ...categoryTids])); + tids = await privileges_1.default.topics.filterTids('topics:read', tids, uid); + let topicData = await Topics.getTopicsByTids(await 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; }; } diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index fc5ea2e926..56541ab2f2 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -33,17 +33,16 @@ interface TopicsType { export default 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 string[] : - await db.getSortedSetRevRangeByScore(tags.map(tag => `tag:${tag}:topics`), 0, -1, '+inf', Date.now() - cutoff) as string[]; + 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(tids.filter(_tid => _tid !== tid))).slice(0, 10) as string[]; + return _.shuffle(_.uniq((await tids).filter((_tid: string) => _tid !== tid))).slice(0, 10) as Promise; } async function getSearchTids( - tid: string, title: string, cid: string, cutoff: number, - uid: string + tid: string, title: string, cid: string, cutoff: number, uid: string ): Promise { - let { ids: tids } = await plugins.hooks.fire('filter:search.query', { + const { ids: tids } = await plugins.hooks.fire('filter:search.query', { index: 'topic', content: title, matchWords: 'any', @@ -52,22 +51,25 @@ export default function Suggested(Topics: TopicsType) { ids: [], }) as { ids: string[] }; - tids = tids.filter(_tid => _tid !== tid); + const filteredTids = tids.filter(_tid => _tid !== tid); + if (cutoff) { - const topicData = await Topics.getTopicsByTids(tids, uid); + const topicData = await Topics.getTopicsByTids(filteredTids, uid); const now = Date.now(); - tids = topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid); + return _.shuffle( + topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid) + ).slice(0, 10) as Promise; } - return _.shuffle(tids).slice(0, 10) as string[]; + return _.shuffle(filteredTids).slice(0, 10) as Promise; } async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { const tids = cutoff === 0 ? - await db.getSortedSetRevRange(`cid:${cid}:tids:lastposttime`, 0, 9) as string[] : - await db.getSortedSetRevRangeByScore(`cid:${cid}:tids:lastposttime`, 0, 10, '+inf', Date.now() - cutoff) as string[]; + 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(tids.filter(_tid => _tid !== tid)) as string[]; + return _.shuffle((await tids).filter((_tid: string) => _tid !== tid)) as Promise; } Topics.getSuggestedTopics = async function ( @@ -80,7 +82,7 @@ export default function Suggested(Topics: TopicsType) { if (!tid) return []; tid = String(tid); - cutoff = cutoff === 0 ? cutoff : (cutoff * 2592000000); + cutoff = cutoff === 0 ? cutoff : cutoff * 2592000000; const { cid, title, tags } = await Topics.getTopicFields(tid, ['cid', 'title', 'tags']); const [tagTids, searchTids] = await Promise.all([ @@ -88,16 +90,16 @@ export default function Suggested(Topics: TopicsType) { getSearchTids(tid, title, cid, cutoff, uid), ]); - let tids = _.uniq([...tagTids, ...searchTids]) as string[]; + let tids = _.uniq([...tagTids, ...searchTids]) as Promise; let categoryTids: string[] = []; - if (stop !== -1 && tids.length < stop - start + 1) { + if (stop !== -1 && (await tids).length < stop - start + 1) { categoryTids = await getCategoryTids(tid, cid, cutoff); } - tids = _.shuffle(_.uniq([...tids, ...categoryTids])) as string[]; - tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; + tids = _.shuffle(_.uniq([...await tids, ...categoryTids])) as Promise; + tids = await privileges.topics.filterTids('topics:read', tids, uid) as Promise; - let topicData = await Topics.getTopicsByTids(tids, uid); + let topicData = await Topics.getTopicsByTids(await 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) 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, From a4ca8fa00c282511ace88ec4daa658483cd4ddd5 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 08:41:06 -0400 Subject: [PATCH 10/13] "Remove ES module exports and add CommonJS exports in suggested.js and suggested.ts files" --- src/topics/suggested.js | 3 +-- src/topics/suggested.ts | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index e89edfad05..c45e08d88f 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -2,8 +2,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = Suggested; /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ const lodash_1 = __importDefault(require("lodash")); @@ -67,3 +65,4 @@ function Suggested(Topics) { return topicData; }; } +module.exports = Suggested; diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 56541ab2f2..4dea84537a 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -30,7 +30,7 @@ interface TopicsType { ) => Promise; } -export default function Suggested(Topics: TopicsType) { +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 : @@ -108,3 +108,5 @@ export default function Suggested(Topics: TopicsType) { return topicData; }; } + +export = Suggested From b03d69b5c02c5343f0e3405190767c0552333829 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 08:51:11 -0400 Subject: [PATCH 11/13] "Changed return type of Suggested function from Promise to string[]" --- src/topics/suggested.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index 4dea84537a..bbe935695a 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -36,7 +36,7 @@ function Suggested(Topics: TopicsType) { 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) as Promise; + return _.shuffle(_.uniq((await tids).filter((_tid: string) => _tid !== tid))).slice(0, 10) as string[]; } async function getSearchTids( From 7a65a1247629db55dcbb4c845f23a77cd6d044ed Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 08:57:17 -0400 Subject: [PATCH 12/13] Remove unnecessary `await` keywords and type casts in `Suggested` function. --- src/topics/suggested.js | 6 +++--- src/topics/suggested.ts | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index c45e08d88f..449ab6a196 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -51,12 +51,12 @@ function Suggested(Topics) { ]); let tids = lodash_1.default.uniq([...tagTids, ...searchTids]); let categoryTids = []; - if (stop !== -1 && (await tids).length < stop - start + 1) { + if (stop !== -1 && (tids).length < stop - start + 1) { categoryTids = await getCategoryTids(tid, cid, cutoff); } - tids = lodash_1.default.shuffle(lodash_1.default.uniq([...await tids, ...categoryTids])); + 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(await 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) diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index bbe935695a..f3c7d4783d 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -58,10 +58,10 @@ function Suggested(Topics: TopicsType) { const now = Date.now(); return _.shuffle( topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid) - ).slice(0, 10) as Promise; + ).slice(0, 10) as string[]; } - return _.shuffle(filteredTids).slice(0, 10) as Promise; + return _.shuffle(filteredTids).slice(0, 10) as string[]; } async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { @@ -69,7 +69,7 @@ function Suggested(Topics: TopicsType) { 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)) as Promise; + return _.shuffle((await tids).filter((_tid: string) => _tid !== tid)) as string[]; } Topics.getSuggestedTopics = async function ( @@ -90,16 +90,16 @@ function Suggested(Topics: TopicsType) { getSearchTids(tid, title, cid, cutoff, uid), ]); - let tids = _.uniq([...tagTids, ...searchTids]) as Promise; + let tids = _.uniq([...tagTids, ...searchTids]) as string[]; let categoryTids: string[] = []; - if (stop !== -1 && (await tids).length < stop - start + 1) { + if (stop !== -1 && (tids).length < stop - start + 1) { categoryTids = await getCategoryTids(tid, cid, cutoff); } - tids = _.shuffle(_.uniq([...await tids, ...categoryTids])) as Promise; - tids = await privileges.topics.filterTids('topics:read', tids, uid) as Promise; + tids = _.shuffle(_.uniq([...tids, ...categoryTids])) as string[]; + tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; - let topicData = await Topics.getTopicsByTids(await tids, uid); + 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) From 85449939b989134d2d55fc3a74a9413de0419328 Mon Sep 17 00:00:00 2001 From: Felix <15-10088@usb.ve> Date: Mon, 14 Oct 2024 09:05:50 -0400 Subject: [PATCH 13/13] "Removed type annotations for return values in Suggested.ts" --- src/topics/suggested.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/topics/suggested.ts b/src/topics/suggested.ts index f3c7d4783d..2bc031664c 100644 --- a/src/topics/suggested.ts +++ b/src/topics/suggested.ts @@ -36,7 +36,7 @@ function Suggested(Topics: TopicsType) { 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) as string[]; + return _.shuffle(_.uniq((await tids).filter((_tid: string) => _tid !== tid))).slice(0, 10); } async function getSearchTids( @@ -58,10 +58,10 @@ function Suggested(Topics: TopicsType) { const now = Date.now(); return _.shuffle( topicData.filter(t => t && t.timestamp > now - cutoff).map(t => t.tid) - ).slice(0, 10) as string[]; + ).slice(0, 10); } - return _.shuffle(filteredTids).slice(0, 10) as string[]; + return _.shuffle(filteredTids).slice(0, 10); } async function getCategoryTids(tid: string, cid: string, cutoff: number): Promise { @@ -69,7 +69,7 @@ function Suggested(Topics: TopicsType) { 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)) as string[]; + return _.shuffle((await tids).filter((_tid: string) => _tid !== tid)); } Topics.getSuggestedTopics = async function ( @@ -77,7 +77,7 @@ function Suggested(Topics: TopicsType) { uid: string, start: number, stop: number, - cutoff: number = 0 + cutoff = 0 ): Promise { if (!tid) return []; @@ -90,13 +90,13 @@ function Suggested(Topics: TopicsType) { getSearchTids(tid, title, cid, cutoff, uid), ]); - let tids = _.uniq([...tagTids, ...searchTids]) as string[]; + 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])) as string[]; + tids = _.shuffle(_.uniq([...tids, ...categoryTids])); tids = await privileges.topics.filterTids('topics:read', tids, uid) as string[]; let topicData = await Topics.getTopicsByTids(tids, uid);