diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/video/video.ts | 63 |
1 files changed, 34 insertions, 29 deletions
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 7acbc60f7..a956da16e 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -201,39 +201,12 @@ type AvailableForListOptions = { | |||
201 | ] | 201 | ] |
202 | } | 202 | } |
203 | 203 | ||
204 | // Force actorId to be a number to avoid SQL injections | ||
205 | const actorIdNumber = parseInt(options.actorId.toString(), 10) | ||
206 | let localVideosReq = '' | ||
207 | if (options.includeLocalVideos === true) { | ||
208 | localVideosReq = ' UNION ALL ' + | ||
209 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
210 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
211 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
212 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
213 | 'WHERE "actor"."serverId" IS NULL' | ||
214 | } | ||
215 | |||
216 | // FIXME: It would be more efficient to use a CTE so we join AFTER the filters, but sequelize does not support it... | 204 | // FIXME: It would be more efficient to use a CTE so we join AFTER the filters, but sequelize does not support it... |
217 | const query: IFindOptions<VideoModel> = { | 205 | const query: IFindOptions<VideoModel> = { |
218 | where: { | 206 | where: { |
219 | id: { | 207 | id: { |
220 | [Sequelize.Op.notIn]: Sequelize.literal( | 208 | [Sequelize.Op.notIn]: Sequelize.literal( |
221 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' | 209 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' |
222 | ), | ||
223 | [ Sequelize.Op.in ]: Sequelize.literal( | ||
224 | '(' + | ||
225 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | ||
226 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | ||
227 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | ||
228 | ' UNION ALL ' + | ||
229 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
230 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
231 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
232 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
233 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' + | ||
234 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | ||
235 | localVideosReq + | ||
236 | ')' | ||
237 | ) | 210 | ) |
238 | }, | 211 | }, |
239 | // Always list public videos | 212 | // Always list public videos |
@@ -254,6 +227,36 @@ type AvailableForListOptions = { | |||
254 | include: [ videoChannelInclude ] | 227 | include: [ videoChannelInclude ] |
255 | } | 228 | } |
256 | 229 | ||
230 | if (options.actorId) { | ||
231 | let localVideosReq = '' | ||
232 | if (options.includeLocalVideos === true) { | ||
233 | localVideosReq = ' UNION ALL ' + | ||
234 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
235 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
236 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
237 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
238 | 'WHERE "actor"."serverId" IS NULL' | ||
239 | } | ||
240 | |||
241 | // Force actorId to be a number to avoid SQL injections | ||
242 | const actorIdNumber = parseInt(options.actorId.toString(), 10) | ||
243 | query.where['id'][ Sequelize.Op.in ] = Sequelize.literal( | ||
244 | '(' + | ||
245 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | ||
246 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | ||
247 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | ||
248 | ' UNION ALL ' + | ||
249 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
250 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
251 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
252 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
253 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' + | ||
254 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | ||
255 | localVideosReq + | ||
256 | ')' | ||
257 | ) | ||
258 | } | ||
259 | |||
257 | if (options.withFiles === true) { | 260 | if (options.withFiles === true) { |
258 | query.include.push({ | 261 | query.include.push({ |
259 | model: VideoFileModel.unscoped(), | 262 | model: VideoFileModel.unscoped(), |
@@ -849,7 +852,8 @@ export class VideoModel extends Model<VideoModel> { | |||
849 | order: getSort(options.sort) | 852 | order: getSort(options.sort) |
850 | } | 853 | } |
851 | 854 | ||
852 | const actorId = options.actorId || (await getServerActor()).id | 855 | // actorId === null has a meaning, so just check undefined |
856 | const actorId = options.actorId !== undefined ? options.actorId : (await getServerActor()).id | ||
853 | 857 | ||
854 | const scopes = { | 858 | const scopes = { |
855 | method: [ | 859 | method: [ |
@@ -926,7 +930,8 @@ export class VideoModel extends Model<VideoModel> { | |||
926 | id: { | 930 | id: { |
927 | [ Sequelize.Op.in ]: Sequelize.literal( | 931 | [ Sequelize.Op.in ]: Sequelize.literal( |
928 | '(' + | 932 | '(' + |
929 | 'SELECT "video"."id" FROM "video" WHERE ' + | 933 | 'SELECT "video"."id" FROM "video" ' + |
934 | 'WHERE ' + | ||
930 | 'lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' + | 935 | 'lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' + |
931 | 'lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' + | 936 | 'lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' + |
932 | 'UNION ALL ' + | 937 | 'UNION ALL ' + |