From 4f5d045960b042eb27e10bac1bdaf1c074c9fa2a Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Thu, 23 Jul 2020 21:30:04 +0200 Subject: harmonize search for libraries --- server/controllers/api/accounts.ts | 3 ++- server/controllers/api/users/my-subscriptions.ts | 11 ++++++-- server/controllers/api/video-channel.ts | 3 +-- .../middlewares/validators/user-subscriptions.ts | 13 +++++++++ server/models/activitypub/actor-follow.ts | 31 +++++++++++++++++----- server/models/video/video-channel.ts | 24 ++++++++++++++--- 6 files changed, 70 insertions(+), 15 deletions(-) (limited to 'server') diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index ccdc610a2..b1c05c6c0 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts @@ -120,7 +120,8 @@ async function listAccountChannels (req: express.Request, res: express.Response) start: req.query.start, count: req.query.count, sort: req.query.sort, - withStats: req.query.withStats + withStats: req.query.withStats, + search: req.query.search } const resultList = await VideoChannelModel.listByAccount(options) diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts index efe1b9bc3..d207a19ae 100644 --- a/server/controllers/api/users/my-subscriptions.ts +++ b/server/controllers/api/users/my-subscriptions.ts @@ -13,7 +13,7 @@ import { userSubscriptionAddValidator, userSubscriptionGetValidator } from '../../../middlewares' -import { areSubscriptionsExistValidator, userSubscriptionsSortValidator, videosSortValidator } from '../../../middlewares/validators' +import { areSubscriptionsExistValidator, userSubscriptionsSortValidator, videosSortValidator, userSubscriptionListValidator } from '../../../middlewares/validators' import { VideoModel } from '../../../models/video/video' import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' import { VideoFilter } from '../../../../shared/models/videos/video-query.type' @@ -45,6 +45,7 @@ mySubscriptionsRouter.get('/me/subscriptions', userSubscriptionsSortValidator, setDefaultSort, setDefaultPagination, + userSubscriptionListValidator, asyncMiddleware(getUserSubscriptions) ) @@ -141,7 +142,13 @@ async function getUserSubscriptions (req: express.Request, res: express.Response const user = res.locals.oauth.token.User const actorId = user.Account.Actor.id - const resultList = await ActorFollowModel.listSubscriptionsForApi(actorId, req.query.start, req.query.count, req.query.sort) + const resultList = await ActorFollowModel.listSubscriptionsForApi({ + actorId, + start: req.query.start, + count: req.query.count, + sort: req.query.sort, + search: req.query.search + }) return res.json(getFormattedObjects(resultList.data, resultList.total)) } diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index d96998209..f705034fd 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -119,8 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) { actorId: serverActor.id, start: req.query.start, count: req.query.count, - sort: req.query.sort, - search: req.query.search + sort: req.query.sort }) return res.json(getFormattedObjects(resultList.data, resultList.total)) diff --git a/server/middlewares/validators/user-subscriptions.ts b/server/middlewares/validators/user-subscriptions.ts index 5d4cc94c5..a54ecb704 100644 --- a/server/middlewares/validators/user-subscriptions.ts +++ b/server/middlewares/validators/user-subscriptions.ts @@ -7,6 +7,18 @@ import { areValidActorHandles, isValidActorHandle } from '../../helpers/custom-v import { toArray } from '../../helpers/custom-validators/misc' import { WEBSERVER } from '../../initializers/constants' +const userSubscriptionListValidator = [ + query('search').optional().not().isEmpty().withMessage('Should have a valid search'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking userSubscriptionListValidator parameters', { parameters: req.query }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + const userSubscriptionAddValidator = [ body('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to follow (username@domain)'), @@ -64,6 +76,7 @@ const userSubscriptionGetValidator = [ export { areSubscriptionsExistValidator, + userSubscriptionListValidator, userSubscriptionAddValidator, userSubscriptionGetValidator } diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index 3e85cc329..529cb35cc 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts @@ -15,14 +15,15 @@ import { Max, Model, Table, - UpdatedAt + UpdatedAt, + Sequelize } from 'sequelize-typescript' import { FollowState } from '../../../shared/models/actors' import { ActorFollow } from '../../../shared/models/actors/follow.model' import { logger } from '../../helpers/logger' import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' import { ServerModel } from '../server/server' -import { createSafeIn, getFollowsSort, getSort } from '../utils' +import { createSafeIn, getFollowsSort, getSort, searchAttribute } from '../utils' import { ActorModel, unusedActorAttributesForAPI } from './actor' import { VideoChannelModel } from '../video/video-channel' import { AccountModel } from '../account/account' @@ -440,16 +441,34 @@ export class ActorFollowModel extends Model { }) } - static listSubscriptionsForApi (actorId: number, start: number, count: number, sort: string) { + static listSubscriptionsForApi (options: { + actorId: number + start: number + count: number + sort: string + search?: string + }) { + const { actorId, start, count, sort } = options + const where = { + actorId: actorId + } + + if (options.search) { + Object.assign(where, { + [Op.or]: [ + searchAttribute(options.search, '$ActorFollowing.preferredUsername$'), + searchAttribute(options.search, '$ActorFollowing.VideoChannel.name$') + ] + }) + } + const query = { attributes: [], distinct: true, offset: start, limit: count, order: getSort(sort), - where: { - actorId: actorId - }, + where, include: [ { attributes: [ 'id' ], diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index f3401fb9c..9da965bbc 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts @@ -315,9 +315,8 @@ export class VideoChannelModel extends Model { start: number count: number sort: string - search?: string }) { - const { actorId, search } = parameters + const { actorId } = parameters const query = { offset: parameters.start, @@ -326,7 +325,7 @@ export class VideoChannelModel extends Model { } const scopes = { - method: [ ScopeNames.FOR_API, { actorId, search } as AvailableForListOptions ] + method: [ ScopeNames.FOR_API, { actorId } as AvailableForListOptions ] } return VideoChannelModel .scope(scopes) @@ -405,7 +404,23 @@ export class VideoChannelModel extends Model { count: number sort: string withStats?: boolean + search?: string }) { + const escapedSearch = VideoModel.sequelize.escape(options.search) + const escapedLikeSearch = VideoModel.sequelize.escape('%' + options.search + '%') + const where = options.search + ? { + [Op.or]: [ + Sequelize.literal( + 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))' + ), + Sequelize.literal( + 'lower(immutable_unaccent("VideoChannelModel"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' + ) + ] + } + : null + const query = { offset: options.start, limit: options.count, @@ -418,7 +433,8 @@ export class VideoChannelModel extends Model { }, required: true } - ] + ], + where } const scopes: string | ScopeOptions | (string | ScopeOptions)[] = [ ScopeNames.WITH_ACTOR ] -- cgit v1.2.3