diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/accounts.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/search.ts | 11 | ||||
-rw-r--r-- | server/controllers/api/video-channel.ts | 4 | ||||
-rw-r--r-- | server/helpers/express-utils.ts | 8 | ||||
-rw-r--r-- | server/lib/activitypub/actor.ts | 31 | ||||
-rw-r--r-- | server/models/video/video.ts | 63 | ||||
-rw-r--r-- | server/tests/api/search/search-activitypub-video-channels.ts | 52 |
7 files changed, 118 insertions, 55 deletions
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 { | |||
11 | import { accountsNameWithHostGetValidator, accountsSortValidator, videosSortValidator } from '../../middlewares/validators' | 11 | import { accountsNameWithHostGetValidator, accountsSortValidator, videosSortValidator } from '../../middlewares/validators' |
12 | import { AccountModel } from '../../models/account/account' | 12 | import { AccountModel } from '../../models/account/account' |
13 | import { VideoModel } from '../../models/video/video' | 13 | import { VideoModel } from '../../models/video/video' |
14 | import { buildNSFWFilter } from '../../helpers/express-utils' | 14 | import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
15 | import { VideoChannelModel } from '../../models/video/video-channel' | 15 | import { VideoChannelModel } from '../../models/video/video-channel' |
16 | 16 | ||
17 | const accountsRouter = express.Router() | 17 | const accountsRouter = express.Router() |
@@ -73,8 +73,10 @@ async function listVideoAccountChannels (req: express.Request, res: express.Resp | |||
73 | 73 | ||
74 | async function listAccountVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 74 | async 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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { buildNSFWFilter } from '../../helpers/express-utils' | 2 | import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
3 | import { getFormattedObjects, getServerActor } from '../../helpers/utils' | 3 | import { getFormattedObjects, getServerActor } from '../../helpers/utils' |
4 | import { VideoModel } from '../../models/video/video' | 4 | import { VideoModel } from '../../models/video/video' |
5 | import { | 5 | import { |
@@ -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 | |||
156 | function 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 | |||
19 | import { sendUpdateActor } from '../../lib/activitypub/send' | 19 | import { sendUpdateActor } from '../../lib/activitypub/send' |
20 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' | 20 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' |
21 | import { createVideoChannel } from '../../lib/video-channel' | 21 | import { createVideoChannel } from '../../lib/video-channel' |
22 | import { buildNSFWFilter, createReqFiles } from '../../helpers/express-utils' | 22 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
23 | import { setAsyncActorKeys } from '../../lib/activitypub' | 23 | import { setAsyncActorKeys } from '../../lib/activitypub' |
24 | import { AccountModel } from '../../models/account/account' | 24 | import { AccountModel } from '../../models/account/account' |
25 | import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' | 25 | import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' |
@@ -210,8 +210,10 @@ async function getVideoChannel (req: express.Request, res: express.Response, nex | |||
210 | 210 | ||
211 | async function listVideoChannelVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 211 | async 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 | ||
98 | function 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 | ||
100 | export { | 107 | export { |
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 | ||
39 | async function getOrCreateActorAndServerAndModel (activityActor: string | ActivityPubActor, recurseIfNeeded = true) { | 39 | async 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 | ||
82 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { | 93 | function 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 | ||
362 | async function refreshActorIfNeeded (actor: ActorModel): Promise<ActorModel> { | 373 | async 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 | |||
27 | describe('Test a ActivityPub video channels search', function () { | 27 | describe('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 | ||