aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-08-24 15:36:50 +0200
committerChocobozzz <me@florianbigard.com>2018-08-27 09:41:54 +0200
commit687d638c2bee0d223f206168173b1b95adbad983 (patch)
tree957741b0ba704562a233181510bb8fda0102c8a5
parentf5b0af50c85e2f8b6b2b054ac1f47123cacbe08d (diff)
downloadPeerTube-687d638c2bee0d223f206168173b1b95adbad983.tar.gz
PeerTube-687d638c2bee0d223f206168173b1b95adbad983.tar.zst
PeerTube-687d638c2bee0d223f206168173b1b95adbad983.zip
Fetch outbox when searching an actor
-rw-r--r--client/src/app/search/search.component.scss2
-rw-r--r--client/src/assets/images/menu/podcasts.svg26
-rw-r--r--server/controllers/api/accounts.ts4
-rw-r--r--server/controllers/api/search.ts11
-rw-r--r--server/controllers/api/video-channel.ts4
-rw-r--r--server/helpers/express-utils.ts8
-rw-r--r--server/lib/activitypub/actor.ts31
-rw-r--r--server/models/video/video.ts63
-rw-r--r--server/tests/api/search/search-activitypub-video-channels.ts52
9 files changed, 118 insertions, 83 deletions
diff --git a/client/src/app/search/search.component.scss b/client/src/app/search/search.component.scss
index be7dd39cf..e5dfddcc5 100644
--- a/client/src/app/search/search.component.scss
+++ b/client/src/app/search/search.component.scss
@@ -113,8 +113,6 @@
113 } 113 }
114 114
115 .video-channel-info { 115 .video-channel-info {
116
117
118 flex-grow: 1; 116 flex-grow: 1;
119 width: fit-content; 117 width: fit-content;
120 118
diff --git a/client/src/assets/images/menu/podcasts.svg b/client/src/assets/images/menu/podcasts.svg
deleted file mode 100644
index cd6efc54e..000000000
--- a/client/src/assets/images/menu/podcasts.svg
+++ /dev/null
@@ -1,26 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3 <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
4 <title>podcasts</title>
5 <desc>Created with Sketch.</desc>
6 <defs>
7 <linearGradient x1="50%" y1="0%" x2="50%" y2="97.3333865%" id="linearGradient-1">
8 <stop stop-color="#808080" offset="0%"></stop>
9 <stop stop-color="#808080" stop-opacity="0.247310915" offset="100%"></stop>
10 </linearGradient>
11 <linearGradient x1="50%" y1="0%" x2="50%" y2="97.8635204%" id="linearGradient-2">
12 <stop stop-color="#808080" offset="0%"></stop>
13 <stop stop-color="#808080" stop-opacity="0.250707654" offset="100%"></stop>
14 </linearGradient>
15 </defs>
16 <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
17 <g id="Artboard-4" transform="translate(-532.000000, -775.000000)">
18 <g id="312" transform="translate(532.000000, 775.000000)">
19 <circle id="Oval-169" fill="#808080" cx="12" cy="10" r="3"></circle>
20 <path d="M16.3851456,13.8501206 C17.4222377,12.6991612 18,11.4167199 18,10 C18,6.74089158 15.2591084,4 12,4 C8.74089158,4 6,6.74089158 6,10 C6,11.4186069 6.57916224,12.7027674 7.61838071,13.8540306 C7.80341316,14.0590125 8.11958231,14.0751848 8.32456427,13.8901523 C8.52954623,13.7051199 8.5457185,13.3889507 8.36068606,13.1839688 C7.47616718,12.2040844 7,11.148292 7,10 C7,7.29317633 9.29317633,5 12,5 C14.7068237,5 17,7.29317633 17,10 C17,11.1466944 16.5249958,12.2010466 15.6422459,13.1807178 C15.4573954,13.3858639 15.4738483,13.7020185 15.6789944,13.886869 C15.8841405,14.0717195 16.2002951,14.0552666 16.3851456,13.8501206 Z" id="Oval-169" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
21 <path d="M17.5678226,18.3077078 C20.3159646,16.4626239 22,13.3733223 22,10 C22,4.4771525 17.5228475,0 12,0 C6.4771525,0 2,4.4771525 2,10 C2,13.3762414 3.68696556,16.4678678 6.43901638,18.3122954 C6.89779529,18.6197696 7.51896613,18.4971129 7.82644029,18.0383339 C8.13391444,17.579555 8.0112577,16.9583842 7.55247879,16.65091 C5.34877306,15.1739839 4,12.7021478 4,10 C4,5.581722 7.581722,2 12,2 C16.418278,2 20,5.581722 20,10 C20,12.699815 18.6535741,15.1697843 16.4529947,16.6472384 C15.9944687,16.9550897 15.8723227,17.5763611 16.180174,18.0348871 C16.4880252,18.4934131 17.1092967,18.6155591 17.5678226,18.3077078 Z" id="Oval-169" fill="url(#linearGradient-2)" fill-rule="nonzero"></path>
22 <path d="M9.32918137,15.9750882 C9.14737952,14.8842771 9.89826062,14 10.9979131,14 L13.0020869,14 C14.1055038,14 14.8534426,14.8793447 14.6708186,15.9750882 L13.6633817,22.0197096 C13.5731485,22.561109 13.0573397,23 12.5010434,23 L11.4989566,23 C10.9472481,23 10.4276519,22.5659113 10.3366183,22.0197096 L9.32918137,15.9750882 Z" id="Rectangle-217" fill="#808080"></path>
23 </g>
24 </g>
25 </g>
26</svg>
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts
index 7b7e5e740..b7691ccba 100644
--- a/server/controllers/api/accounts.ts
+++ b/server/controllers/api/accounts.ts
@@ -11,7 +11,7 @@ import {
11import { accountsNameWithHostGetValidator, accountsSortValidator, videosSortValidator } from '../../middlewares/validators' 11import { accountsNameWithHostGetValidator, accountsSortValidator, videosSortValidator } from '../../middlewares/validators'
12import { AccountModel } from '../../models/account/account' 12import { AccountModel } from '../../models/account/account'
13import { VideoModel } from '../../models/video/video' 13import { VideoModel } from '../../models/video/video'
14import { buildNSFWFilter } from '../../helpers/express-utils' 14import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
15import { VideoChannelModel } from '../../models/video/video-channel' 15import { VideoChannelModel } from '../../models/video/video-channel'
16 16
17const accountsRouter = express.Router() 17const accountsRouter = express.Router()
@@ -73,8 +73,10 @@ async function listVideoAccountChannels (req: express.Request, res: express.Resp
73 73
74async function listAccountVideos (req: express.Request, res: express.Response, next: express.NextFunction) { 74async function listAccountVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
75 const account: AccountModel = res.locals.account 75 const account: AccountModel = res.locals.account
76 const actorId = isUserAbleToSearchRemoteURI(res) ? null : undefined
76 77
77 const resultList = await VideoModel.listForApi({ 78 const resultList = await VideoModel.listForApi({
79 actorId,
78 start: req.query.start, 80 start: req.query.start,
79 count: req.query.count, 81 count: req.query.count,
80 sort: req.query.sort, 82 sort: req.query.sort,
diff --git a/server/controllers/api/search.ts b/server/controllers/api/search.ts
index 959d79855..bb7174891 100644
--- a/server/controllers/api/search.ts
+++ b/server/controllers/api/search.ts
@@ -1,5 +1,5 @@
1import * as express from 'express' 1import * as express from 'express'
2import { buildNSFWFilter } from '../../helpers/express-utils' 2import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
3import { getFormattedObjects, getServerActor } from '../../helpers/utils' 3import { getFormattedObjects, getServerActor } from '../../helpers/utils'
4import { VideoModel } from '../../models/video/video' 4import { VideoModel } from '../../models/video/video'
5import { 5import {
@@ -88,7 +88,7 @@ async function searchVideoChannelURI (search: string, isWebfingerSearch: boolean
88 88
89 if (isUserAbleToSearchRemoteURI(res)) { 89 if (isUserAbleToSearchRemoteURI(res)) {
90 try { 90 try {
91 const actor = await getOrCreateActorAndServerAndModel(uri) 91 const actor = await getOrCreateActorAndServerAndModel(uri, true, true)
92 videoChannel = actor.VideoChannel 92 videoChannel = actor.VideoChannel
93 } catch (err) { 93 } catch (err) {
94 logger.info('Cannot search remote video channel %s.', uri, { err }) 94 logger.info('Cannot search remote video channel %s.', uri, { err })
@@ -152,10 +152,3 @@ async function searchVideoURI (url: string, res: express.Response) {
152 data: video ? [ video.toFormattedJSON() ] : [] 152 data: video ? [ video.toFormattedJSON() ] : []
153 }) 153 })
154} 154}
155
156function isUserAbleToSearchRemoteURI (res: express.Response) {
157 const user: User = res.locals.oauth ? res.locals.oauth.token.User : undefined
158
159 return CONFIG.SEARCH.REMOTE_URI.ANONYMOUS === true ||
160 (CONFIG.SEARCH.REMOTE_URI.USERS === true && user !== undefined)
161}
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts
index bd08d7a08..a7a36080b 100644
--- a/server/controllers/api/video-channel.ts
+++ b/server/controllers/api/video-channel.ts
@@ -19,7 +19,7 @@ import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../m
19import { sendUpdateActor } from '../../lib/activitypub/send' 19import { sendUpdateActor } from '../../lib/activitypub/send'
20import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' 20import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
21import { createVideoChannel } from '../../lib/video-channel' 21import { createVideoChannel } from '../../lib/video-channel'
22import { buildNSFWFilter, createReqFiles } from '../../helpers/express-utils' 22import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
23import { setAsyncActorKeys } from '../../lib/activitypub' 23import { setAsyncActorKeys } from '../../lib/activitypub'
24import { AccountModel } from '../../models/account/account' 24import { AccountModel } from '../../models/account/account'
25import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' 25import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers'
@@ -210,8 +210,10 @@ async function getVideoChannel (req: express.Request, res: express.Response, nex
210 210
211async function listVideoChannelVideos (req: express.Request, res: express.Response, next: express.NextFunction) { 211async function listVideoChannelVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
212 const videoChannelInstance: VideoChannelModel = res.locals.videoChannel 212 const videoChannelInstance: VideoChannelModel = res.locals.videoChannel
213 const actorId = isUserAbleToSearchRemoteURI(res) ? null : undefined
213 214
214 const resultList = await VideoModel.listForApi({ 215 const resultList = await VideoModel.listForApi({
216 actorId,
215 start: req.query.start, 217 start: req.query.start,
216 count: req.query.count, 218 count: req.query.count,
217 sort: req.query.sort, 219 sort: req.query.sort,
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts
index 1d7bee87e..b715fb7d0 100644
--- a/server/helpers/express-utils.ts
+++ b/server/helpers/express-utils.ts
@@ -95,11 +95,19 @@ function createReqFiles (
95 return multer({ storage }).fields(fields) 95 return multer({ storage }).fields(fields)
96} 96}
97 97
98function isUserAbleToSearchRemoteURI (res: express.Response) {
99 const user: User = res.locals.oauth ? res.locals.oauth.token.User : undefined
100
101 return CONFIG.SEARCH.REMOTE_URI.ANONYMOUS === true ||
102 (CONFIG.SEARCH.REMOTE_URI.USERS === true && user !== undefined)
103}
104
98// --------------------------------------------------------------------------- 105// ---------------------------------------------------------------------------
99 106
100export { 107export {
101 buildNSFWFilter, 108 buildNSFWFilter,
102 getHostWithPort, 109 getHostWithPort,
110 isUserAbleToSearchRemoteURI,
103 badRequest, 111 badRequest,
104 createReqFiles, 112 createReqFiles,
105 cleanUpReqFiles 113 cleanUpReqFiles
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index 22e1c9f19..1657262d7 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -36,8 +36,13 @@ function setAsyncActorKeys (actor: ActorModel) {
36 }) 36 })
37} 37}
38 38
39async function getOrCreateActorAndServerAndModel (activityActor: string | ActivityPubActor, recurseIfNeeded = true) { 39async function getOrCreateActorAndServerAndModel (
40 activityActor: string | ActivityPubActor,
41 recurseIfNeeded = true,
42 updateCollections = false
43) {
40 const actorUrl = getActorUrl(activityActor) 44 const actorUrl = getActorUrl(activityActor)
45 let created = false
41 46
42 let actor = await ActorModel.loadByUrl(actorUrl) 47 let actor = await ActorModel.loadByUrl(actorUrl)
43 // Orphan actor (not associated to an account of channel) so recreate it 48 // Orphan actor (not associated to an account of channel) so recreate it
@@ -68,15 +73,21 @@ async function getOrCreateActorAndServerAndModel (activityActor: string | Activi
68 } 73 }
69 74
70 actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor) 75 actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor)
76 created = true
71 } 77 }
72 78
73 if (actor.Account) actor.Account.Actor = actor 79 if (actor.Account) actor.Account.Actor = actor
74 if (actor.VideoChannel) actor.VideoChannel.Actor = actor 80 if (actor.VideoChannel) actor.VideoChannel.Actor = actor
75 81
76 actor = await retryTransactionWrapper(refreshActorIfNeeded, actor) 82 const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor)
77 if (!actor) throw new Error('Actor ' + actor.url + ' does not exist anymore.') 83 if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.')
78 84
79 return actor 85 if ((created === true || refreshed === true) && updateCollections === true) {
86 const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' }
87 await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
88 }
89
90 return actorRefreshed
80} 91}
81 92
82function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { 93function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) {
@@ -359,8 +370,8 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu
359 return videoChannelCreated 370 return videoChannelCreated
360} 371}
361 372
362async function refreshActorIfNeeded (actor: ActorModel): Promise<ActorModel> { 373async function refreshActorIfNeeded (actor: ActorModel): Promise<{ actor: ActorModel, refreshed: boolean }> {
363 if (!actor.isOutdated()) return actor 374 if (!actor.isOutdated()) return { actor, refreshed: false }
364 375
365 try { 376 try {
366 const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) 377 const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost())
@@ -369,12 +380,12 @@ async function refreshActorIfNeeded (actor: ActorModel): Promise<ActorModel> {
369 if (statusCode === 404) { 380 if (statusCode === 404) {
370 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) 381 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
371 actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() 382 actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy()
372 return undefined 383 return { actor: undefined, refreshed: false }
373 } 384 }
374 385
375 if (result === undefined) { 386 if (result === undefined) {
376 logger.warn('Cannot fetch remote actor in refresh actor.') 387 logger.warn('Cannot fetch remote actor in refresh actor.')
377 return actor 388 return { actor, refreshed: false }
378 } 389 }
379 390
380 return sequelizeTypescript.transaction(async t => { 391 return sequelizeTypescript.transaction(async t => {
@@ -403,10 +414,10 @@ async function refreshActorIfNeeded (actor: ActorModel): Promise<ActorModel> {
403 await actor.VideoChannel.save({ transaction: t }) 414 await actor.VideoChannel.save({ transaction: t })
404 } 415 }
405 416
406 return actor 417 return { refreshed: true, actor }
407 }) 418 })
408 } catch (err) { 419 } catch (err) {
409 logger.warn('Cannot refresh actor.', { err }) 420 logger.warn('Cannot refresh actor.', { err })
410 return actor 421 return { actor, refreshed: false }
411 } 422 }
412} 423}
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 ' +
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts
index 512cb32fd..a287c5bdf 100644
--- a/server/tests/api/search/search-activitypub-video-channels.ts
+++ b/server/tests/api/search/search-activitypub-video-channels.ts
@@ -8,11 +8,11 @@ import {
8 deleteVideoChannel, 8 deleteVideoChannel,
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 flushTests, 10 flushTests,
11 getVideoChannelsList, 11 getVideoChannelsList, getVideoChannelVideos,
12 killallServers, 12 killallServers,
13 ServerInfo, 13 ServerInfo,
14 setAccessTokensToServers, 14 setAccessTokensToServers,
15 updateMyUser, 15 updateMyUser, updateVideo,
16 updateVideoChannel, 16 updateVideoChannel,
17 uploadVideo, 17 uploadVideo,
18 userLogin, 18 userLogin,
@@ -27,6 +27,8 @@ const expect = chai.expect
27describe('Test a ActivityPub video channels search', function () { 27describe('Test a ActivityPub video channels search', function () {
28 let servers: ServerInfo[] 28 let servers: ServerInfo[]
29 let userServer2Token: string 29 let userServer2Token: string
30 let videoServer2UUID: string
31 let channelIdServer2: number
30 32
31 before(async function () { 33 before(async function () {
32 this.timeout(120000) 34 this.timeout(120000)
@@ -56,10 +58,10 @@ describe('Test a ActivityPub video channels search', function () {
56 displayName: 'Channel 1 server 2' 58 displayName: 'Channel 1 server 2'
57 } 59 }
58 const resChannel = await addVideoChannel(servers[1].url, userServer2Token, channel) 60 const resChannel = await addVideoChannel(servers[1].url, userServer2Token, channel)
59 const channelId = resChannel.body.videoChannel.id 61 channelIdServer2 = resChannel.body.videoChannel.id
60 62
61 await uploadVideo(servers[1].url, userServer2Token, { name: 'video 1 server 2', channelId }) 63 const res = await uploadVideo(servers[1].url, userServer2Token, { name: 'video 1 server 2', channelId: channelIdServer2 })
62 await uploadVideo(servers[1].url, userServer2Token, { name: 'video 2 server 2', channelId }) 64 videoServer2UUID = res.body.video.uuid
63 } 65 }
64 66
65 await waitJobs(servers) 67 await waitJobs(servers)
@@ -129,6 +131,23 @@ describe('Test a ActivityPub video channels search', function () {
129 expect(res.body.data[2].name).to.equal('root_channel') 131 expect(res.body.data[2].name).to.equal('root_channel')
130 }) 132 })
131 133
134 it('Should list video channel videos of server 2 without token', async function () {
135 this.timeout(30000)
136
137 await waitJobs(servers)
138
139 const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:9002', 0, 5)
140 expect(res.body.total).to.equal(0)
141 expect(res.body.data).to.have.lengthOf(0)
142 })
143
144 it('Should list video channel videos of server 2 with token', async function () {
145 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5)
146
147 expect(res.body.total).to.equal(1)
148 expect(res.body.data[0].name).to.equal('video 1 server 2')
149 })
150
132 it('Should update video channel of server 2, and refresh it on server 1', async function () { 151 it('Should update video channel of server 2, and refresh it on server 1', async function () {
133 this.timeout(60000) 152 this.timeout(60000)
134 153
@@ -151,6 +170,29 @@ describe('Test a ActivityPub video channels search', function () {
151 // expect(videoChannel.ownerAccount.displayName).to.equal('user updated') 170 // expect(videoChannel.ownerAccount.displayName).to.equal('user updated')
152 }) 171 })
153 172
173 it('Should update and add a video on server 2, and update it on server 1 after a search', async function () {
174 this.timeout(60000)
175
176 await updateVideo(servers[1].url, userServer2Token, videoServer2UUID, { name: 'video 1 updated' })
177 await uploadVideo(servers[1].url, userServer2Token, { name: 'video 2 server 2', channelId: channelIdServer2 })
178
179 await waitJobs(servers)
180
181 // Expire video channel
182 await wait(10000)
183
184 const search = 'http://localhost:9002/video-channels/channel1_server2'
185 await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
186
187 await waitJobs(servers)
188
189 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5, '-createdAt')
190
191 expect(res.body.total).to.equal(2)
192 expect(res.body.data[0].name).to.equal('video 2 server 2')
193 expect(res.body.data[1].name).to.equal('video 1 updated')
194 })
195
154 it('Should delete video channel of server 2, and delete it on server 1', async function () { 196 it('Should delete video channel of server 2, and delete it on server 1', async function () {
155 this.timeout(60000) 197 this.timeout(60000)
156 198