From 74a4d53110ebc073dafeb74a7ac815fe00f4706b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 24 Mar 2021 09:16:48 +0100 Subject: [PATCH] Add server hooks for search endpoint --- server/controllers/api/search.ts | 37 +++++++---- .../fixtures/peertube-plugin-test/main.js | 24 +++++++ server/tests/plugins/filter-hooks.ts | 62 ++++++++++++++++++- shared/models/plugins/server-hook.model.ts | 10 +++ 4 files changed, 121 insertions(+), 12 deletions(-) diff --git a/server/controllers/api/search.ts b/server/controllers/api/search.ts index 57357b1e8..f0cdf3a89 100644 --- a/server/controllers/api/search.ts +++ b/server/controllers/api/search.ts @@ -3,6 +3,7 @@ import { sanitizeUrl } from '@server/helpers/core-utils' import { doJSONRequest } from '@server/helpers/requests' import { CONFIG } from '@server/initializers/config' import { getOrCreateVideoAndAccountAndChannel } from '@server/lib/activitypub/videos' +import { Hooks } from '@server/lib/plugins/hooks' import { AccountBlocklistModel } from '@server/models/account/account-blocklist' import { getServerActor } from '@server/models/application/application' import { ServerBlocklistModel } from '@server/models/server/server-blocklist' @@ -22,8 +23,8 @@ import { paginationValidator, setDefaultPagination, setDefaultSearchSort, - videoChannelsSearchSortValidator, videoChannelsListSearchValidator, + videoChannelsSearchSortValidator, videosSearchSortValidator, videosSearchValidator } from '../../middlewares' @@ -87,7 +88,7 @@ function searchVideoChannels (req: express.Request, res: express.Response) { async function searchVideoChannelsIndex (query: VideoChannelsSearchQuery, res: express.Response) { const result = await buildMutedForSearchIndex(res) - const body = Object.assign(query, result) + const body = await Hooks.wrapObject(Object.assign(query, result), 'filter:api.search.video-channels.index.list.params') const url = sanitizeUrl(CONFIG.SEARCH.SEARCH_INDEX.URL) + '/api/v1/search/video-channels' @@ -95,8 +96,9 @@ async function searchVideoChannelsIndex (query: VideoChannelsSearchQuery, res: e logger.debug('Doing video channels search index request on %s.', url, { body }) const { body: searchIndexResult } = await doJSONRequest>(url, { method: 'POST', json: body }) + const jsonResult = await Hooks.wrapObject(searchIndexResult, 'filter:api.search.video-channels.index.list.result') - return res.json(searchIndexResult) + return res.json(jsonResult) } catch (err) { logger.warn('Cannot use search index to make video channels search.', { err }) @@ -107,14 +109,19 @@ async function searchVideoChannelsIndex (query: VideoChannelsSearchQuery, res: e async function searchVideoChannelsDB (query: VideoChannelsSearchQuery, res: express.Response) { const serverActor = await getServerActor() - const options = { + const apiOptions = await Hooks.wrapObject({ actorId: serverActor.id, search: query.search, start: query.start, count: query.count, sort: query.sort - } - const resultList = await VideoChannelModel.searchForApi(options) + }, 'filter:api.search.video-channels.local.list.params') + + const resultList = await Hooks.wrapPromiseFun( + VideoChannelModel.searchForApi, + apiOptions, + 'filter:api.search.video-channels.local.list.result' + ) return res.json(getFormattedObjects(resultList.data, resultList.total)) } @@ -168,7 +175,7 @@ function searchVideos (req: express.Request, res: express.Response) { async function searchVideosIndex (query: VideosSearchQuery, res: express.Response) { const result = await buildMutedForSearchIndex(res) - const body: VideosSearchQuery = Object.assign(query, result) + let body: VideosSearchQuery = Object.assign(query, result) // Use the default instance NSFW policy if not specified if (!body.nsfw) { @@ -181,14 +188,17 @@ async function searchVideosIndex (query: VideosSearchQuery, res: express.Respons : 'both' } + body = await Hooks.wrapObject(body, 'filter:api.search.videos.index.list.params') + const url = sanitizeUrl(CONFIG.SEARCH.SEARCH_INDEX.URL) + '/api/v1/search/videos' try { logger.debug('Doing videos search index request on %s.', url, { body }) const { body: searchIndexResult } = await doJSONRequest>(url, { method: 'POST', json: body }) + const jsonResult = await Hooks.wrapObject(searchIndexResult, 'filter:api.search.videos.index.list.result') - return res.json(searchIndexResult) + return res.json(jsonResult) } catch (err) { logger.warn('Cannot use search index to make video search.', { err }) @@ -197,13 +207,18 @@ async function searchVideosIndex (query: VideosSearchQuery, res: express.Respons } async function searchVideosDB (query: VideosSearchQuery, res: express.Response) { - const options = Object.assign(query, { + const apiOptions = await Hooks.wrapObject(Object.assign(query, { includeLocalVideos: true, nsfw: buildNSFWFilter(res, query.nsfw), filter: query.filter, user: res.locals.oauth ? res.locals.oauth.token.User : undefined - }) - const resultList = await VideoModel.searchAndPopulateAccountAndServer(options) + }), 'filter:api.search.videos.local.list.params') + + const resultList = await Hooks.wrapPromiseFun( + VideoModel.searchAndPopulateAccountAndServer, + apiOptions, + 'filter:api.search.videos.local.list.result' + ) return res.json(getFormattedObjects(resultList.data, resultList.total)) } diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index dfcc874d4..ee0bc39f3 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js @@ -230,6 +230,30 @@ async function register ({ registerHook, registerSetting, settingsManager, stora } } }) + + { + const searchHooks = [ + 'filter:api.search.videos.local.list.params', + 'filter:api.search.videos.local.list.result', + 'filter:api.search.videos.index.list.params', + 'filter:api.search.videos.index.list.result', + 'filter:api.search.video-channels.local.list.params', + 'filter:api.search.video-channels.local.list.result', + 'filter:api.search.video-channels.index.list.params', + 'filter:api.search.video-channels.index.list.result', + ] + + for (const h of searchHooks) { + registerHook({ + target: h, + handler: (obj) => { + peertubeHelpers.logger.debug('Run hook %s.', h) + + return obj + } + }) + } + } } async function unregister () { diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index be47b20ba..6f7fec767 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts @@ -7,6 +7,7 @@ import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-code import { addVideoCommentReply, addVideoCommentThread, + advancedVideosSearch, createLive, createVideoPlaylist, doubleFollow, @@ -25,6 +26,7 @@ import { installPlugin, makeRawRequest, registerUser, + searchVideo, setAccessTokensToServers, setDefaultVideoChannel, updateCustomSubConfig, @@ -33,7 +35,7 @@ import { uploadVideoAndGetId, waitJobs } from '../../../shared/extra-utils' -import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../shared/extra-utils/server/servers' +import { cleanupTests, flushAndRunMultipleServers, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers' import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports' import { VideoDetails, @@ -44,6 +46,7 @@ import { VideoPrivacy } from '../../../shared/models/videos' import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' +import { advancedVideoChannelSearch } from '@shared/extra-utils/search/video-channels' const expect = chai.expect @@ -468,6 +471,63 @@ describe('Test plugin filter hooks', function () { }) }) + describe('Search filters', function () { + + before(async function () { + await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { + search: { + searchIndex: { + enabled: true, + isDefaultSearch: false, + disableLocalSearch: false + } + } + }) + }) + + it('Should run filter:api.search.videos.local.list.{params,result}', async function () { + await advancedVideosSearch(servers[0].url, { + search: 'Sun Quan' + }) + + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.local.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.local.list.result', 1) + }) + + it('Should run filter:api.search.videos.index.list.{params,result}', async function () { + await advancedVideosSearch(servers[0].url, { + search: 'Sun Quan', + searchTarget: 'search-index' + }) + + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.local.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.local.list.result', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.index.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.videos.index.list.result', 1) + }) + + it('Should run filter:api.search.video-channels.local.list.{params,result}', async function () { + await advancedVideoChannelSearch(servers[0].url, { + search: 'Sun Ce' + }) + + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.local.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.local.list.result', 1) + }) + + it('Should run filter:api.search.video-channels.index.list.{params,result}', async function () { + await advancedVideoChannelSearch(servers[0].url, { + search: 'Sun Ce', + searchTarget: 'search-index' + }) + + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.local.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.local.list.result', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.params', 1) + await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.result', 1) + }) + }) + after(async function () { await cleanupTests(servers) }) diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts index d28f76dfe..88277af5a 100644 --- a/shared/models/plugins/server-hook.model.ts +++ b/shared/models/plugins/server-hook.model.ts @@ -18,6 +18,16 @@ export const serverFilterHookObject = { 'filter:api.user.me.videos.list.params': true, 'filter:api.user.me.videos.list.result': true, + // Filter params/results to search videos/channels in the DB or on the remote index + 'filter:api.search.videos.local.list.params': true, + 'filter:api.search.videos.local.list.result': true, + 'filter:api.search.videos.index.list.params': true, + 'filter:api.search.videos.index.list.result': true, + 'filter:api.search.video-channels.local.list.params': true, + 'filter:api.search.video-channels.local.list.result': true, + 'filter:api.search.video-channels.index.list.params': true, + 'filter:api.search.video-channels.index.list.result': true, + // Filter the result of the get function // Used to get detailed video information (video watch page for example) 'filter:api.video.get.result': true,