Search video channel handle/uri
This commit is contained in:
parent
aa55a4da42
commit
f5b0af50c8
18 changed files with 303 additions and 65 deletions
|
@ -1,6 +1,6 @@
|
|||
<div *ngIf="account" class="row">
|
||||
<a
|
||||
*ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.name ]"
|
||||
*ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"
|
||||
class="video-channel" i18n-title title="See this video channel"
|
||||
>
|
||||
<img [src]="videoChannel.avatarUrl" alt="Avatar" />
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
|
||||
<div *ngFor="let videoChannel of videoChannels" class="video-channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]">
|
||||
<img [src]="videoChannel.avatarUrl" alt="Avatar" />
|
||||
</a>
|
||||
|
||||
<div class="video-channel-info">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]" class="video-channel-names" i18n-title title="Go to the channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Go to the channel">
|
||||
<div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.name }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.nameWithHost }}</div>
|
||||
</a>
|
||||
|
||||
<div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
<div class="video-channels">
|
||||
<div *ngFor="let videoChannel of videoChannels" class="video-channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]">
|
||||
<img [src]="videoChannel.avatarUrl" alt="Avatar" />
|
||||
</a>
|
||||
|
||||
<div class="video-channel-info">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]" class="video-channel-names" i18n-title title="Go to the channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Go to the channel">
|
||||
<div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.name }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.nameWithHost }}</div>
|
||||
</a>
|
||||
|
||||
<div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<div class="video-channel-buttons">
|
||||
<my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
|
||||
|
||||
<my-edit-button [routerLink]="[ 'update', videoChannel.name ]"></my-edit-button>
|
||||
<my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,11 +11,4 @@
|
|||
.actor-name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
my-subscribe-button {
|
||||
/deep/ span[role=button] {
|
||||
padding: 7px 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,14 +27,14 @@
|
|||
</div>
|
||||
|
||||
<div *ngFor="let videoChannel of videoChannels" class="entry video-channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]">
|
||||
<img [src]="videoChannel.avatarUrl" alt="Avatar" />
|
||||
</a>
|
||||
|
||||
<div class="video-channel-info">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.name ]" class="video-channel-names">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names">
|
||||
<div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.name }}</div>
|
||||
<div class="video-channel-name">{{ videoChannel.nameWithHost }}</div>
|
||||
</a>
|
||||
|
||||
<div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
|
||||
|
|
|
@ -4,14 +4,7 @@ import { Injectable } from '@angular/core'
|
|||
import { Observable } from 'rxjs'
|
||||
import { Video as VideoServerModel, VideoDetails as VideoDetailsServerModel } from '../../../../../shared'
|
||||
import { ResultList } from '../../../../../shared/models/result-list.model'
|
||||
import {
|
||||
UserVideoRate,
|
||||
UserVideoRateUpdate,
|
||||
VideoChannel,
|
||||
VideoFilter,
|
||||
VideoRateType,
|
||||
VideoUpdate
|
||||
} from '../../../../../shared/models/videos'
|
||||
import { UserVideoRate, UserVideoRateUpdate, VideoFilter, VideoRateType, VideoUpdate } from '../../../../../shared/models/videos'
|
||||
import { FeedFormat } from '../../../../../shared/models/feeds/feed-format.enum'
|
||||
import { environment } from '../../../environments/environment'
|
||||
import { ComponentPagination } from '../rest/component-pagination.model'
|
||||
|
@ -28,6 +21,7 @@ import { AccountService } from '@app/shared/account/account.service'
|
|||
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
|
||||
import { ServerService } from '@app/core'
|
||||
import { UserSubscriptionService } from '@app/shared/user-subscription'
|
||||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||
|
||||
@Injectable()
|
||||
export class VideoService {
|
||||
|
@ -151,7 +145,7 @@ export class VideoService {
|
|||
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||
|
||||
return this.authHttp
|
||||
.get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.name + '/videos', { params })
|
||||
.get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params })
|
||||
.pipe(
|
||||
switchMap(res => this.extractVideos(res)),
|
||||
catchError(err => this.restExtractor.handleError(err))
|
||||
|
|
|
@ -41,7 +41,6 @@ searchRouter.get('/video-channels',
|
|||
videoChannelsSearchSortValidator,
|
||||
setDefaultSearchSort,
|
||||
optionalAuthenticate,
|
||||
commonVideosFiltersValidator,
|
||||
videoChannelsSearchValidator,
|
||||
asyncMiddleware(searchVideoChannels)
|
||||
)
|
||||
|
@ -59,9 +58,9 @@ function searchVideoChannels (req: express.Request, res: express.Response) {
|
|||
const isURISearch = search.startsWith('http://') || search.startsWith('https://')
|
||||
|
||||
const parts = search.split('@')
|
||||
const isHandleSearch = parts.length === 2 && parts.every(p => p.indexOf(' ') === -1)
|
||||
const isWebfingerSearch = parts.length === 2 && parts.every(p => p.indexOf(' ') === -1)
|
||||
|
||||
if (isURISearch || isHandleSearch) return searchVideoChannelURI(search, isHandleSearch, res)
|
||||
if (isURISearch || isWebfingerSearch) return searchVideoChannelURI(search, isWebfingerSearch, res)
|
||||
|
||||
return searchVideoChannelsDB(query, res)
|
||||
}
|
||||
|
@ -81,17 +80,21 @@ async function searchVideoChannelsDB (query: VideoChannelsSearchQuery, res: expr
|
|||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function searchVideoChannelURI (search: string, isHandleSearch: boolean, res: express.Response) {
|
||||
async function searchVideoChannelURI (search: string, isWebfingerSearch: boolean, res: express.Response) {
|
||||
let videoChannel: VideoChannelModel
|
||||
let uri = search
|
||||
|
||||
if (isWebfingerSearch) uri = await loadActorUrlOrGetFromWebfinger(search)
|
||||
|
||||
if (isUserAbleToSearchRemoteURI(res)) {
|
||||
let uri = search
|
||||
if (isHandleSearch) uri = await loadActorUrlOrGetFromWebfinger(search)
|
||||
|
||||
const actor = await getOrCreateActorAndServerAndModel(uri)
|
||||
videoChannel = actor.VideoChannel
|
||||
try {
|
||||
const actor = await getOrCreateActorAndServerAndModel(uri)
|
||||
videoChannel = actor.VideoChannel
|
||||
} catch (err) {
|
||||
logger.info('Cannot search remote video channel %s.', uri, { err })
|
||||
}
|
||||
} else {
|
||||
videoChannel = await VideoChannelModel.loadByUrlAndPopulateAccount(search)
|
||||
videoChannel = await VideoChannelModel.loadByUrlAndPopulateAccount(uri)
|
||||
}
|
||||
|
||||
return res.json({
|
||||
|
@ -138,7 +141,7 @@ async function searchVideoURI (url: string, res: express.Response) {
|
|||
const result = await getOrCreateVideoAndAccountAndChannel(url, syncParam)
|
||||
video = result ? result.video : undefined
|
||||
} catch (err) {
|
||||
logger.info('Cannot search remote video %s.', url)
|
||||
logger.info('Cannot search remote video %s.', url, { err })
|
||||
}
|
||||
} else {
|
||||
video = await VideoModel.loadByUrlAndPopulateAccount(url)
|
||||
|
|
|
@ -3,6 +3,7 @@ import { WebFingerData } from '../../shared'
|
|||
import { ActorModel } from '../models/activitypub/actor'
|
||||
import { isTestInstance } from './core-utils'
|
||||
import { isActivityPubUrlValid } from './custom-validators/activitypub/misc'
|
||||
import { CONFIG } from '../initializers'
|
||||
|
||||
const webfinger = new WebFinger({
|
||||
webfist_fallback: false,
|
||||
|
@ -13,8 +14,14 @@ const webfinger = new WebFinger({
|
|||
|
||||
async function loadActorUrlOrGetFromWebfinger (uri: string) {
|
||||
const [ name, host ] = uri.split('@')
|
||||
let actor: ActorModel
|
||||
|
||||
if (host === CONFIG.WEBSERVER.HOST) {
|
||||
actor = await ActorModel.loadLocalByName(name)
|
||||
} else {
|
||||
actor = await ActorModel.loadByNameAndHost(name, host)
|
||||
}
|
||||
|
||||
const actor = await ActorModel.loadByNameAndHost(name, host)
|
||||
if (actor) return actor.url
|
||||
|
||||
return getUrlFromWebfinger(uri)
|
||||
|
|
|
@ -44,7 +44,7 @@ const SORTABLE_COLUMNS = {
|
|||
FOLLOWING: [ 'createdAt' ],
|
||||
|
||||
VIDEOS_SEARCH: [ 'match', 'name', 'duration', 'createdAt', 'publishedAt', 'views', 'likes' ],
|
||||
VIDEO_CHANNELS_SEARCH: [ 'match', 'displayName' ]
|
||||
VIDEO_CHANNELS_SEARCH: [ 'match', 'displayName', 'createdAt' ]
|
||||
}
|
||||
|
||||
const OAUTH_LIFETIME = {
|
||||
|
|
|
@ -48,7 +48,7 @@ async function getOrCreateActorAndServerAndModel (activityActor: string | Activi
|
|||
|
||||
// We don't have this actor in our database, fetch it on remote
|
||||
if (!actor) {
|
||||
const result = await fetchRemoteActor(actorUrl)
|
||||
const { result } = await fetchRemoteActor(actorUrl)
|
||||
if (result === undefined) throw new Error('Cannot fetch remote actor.')
|
||||
|
||||
// Create the attributed to actor
|
||||
|
@ -70,7 +70,13 @@ async function getOrCreateActorAndServerAndModel (activityActor: string | Activi
|
|||
actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor)
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(refreshActorIfNeeded, actor)
|
||||
if (actor.Account) actor.Account.Actor = actor
|
||||
if (actor.VideoChannel) actor.VideoChannel.Actor = actor
|
||||
|
||||
actor = await retryTransactionWrapper(refreshActorIfNeeded, actor)
|
||||
if (!actor) throw new Error('Actor ' + actor.url + ' does not exist anymore.')
|
||||
|
||||
return actor
|
||||
}
|
||||
|
||||
function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) {
|
||||
|
@ -264,7 +270,7 @@ type FetchRemoteActorResult = {
|
|||
avatarName?: string
|
||||
attributedTo: ActivityPubAttributedTo[]
|
||||
}
|
||||
async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResult> {
|
||||
async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: number, result: FetchRemoteActorResult }> {
|
||||
const options = {
|
||||
uri: actorUrl,
|
||||
method: 'GET',
|
||||
|
@ -281,7 +287,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
|
|||
|
||||
if (isActorObjectValid(actorJSON) === false) {
|
||||
logger.debug('Remote actor JSON is not valid.', { actorJSON: actorJSON })
|
||||
return undefined
|
||||
return { result: undefined, statusCode: requestResult.response.statusCode }
|
||||
}
|
||||
|
||||
const followersCount = await fetchActorTotalItems(actorJSON.followers)
|
||||
|
@ -307,12 +313,15 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
|
|||
|
||||
const name = actorJSON.name || actorJSON.preferredUsername
|
||||
return {
|
||||
actor,
|
||||
name,
|
||||
avatarName,
|
||||
summary: actorJSON.summary,
|
||||
support: actorJSON.support,
|
||||
attributedTo: actorJSON.attributedTo
|
||||
statusCode: requestResult.response.statusCode,
|
||||
result: {
|
||||
actor,
|
||||
name,
|
||||
avatarName,
|
||||
summary: actorJSON.summary,
|
||||
support: actorJSON.support,
|
||||
attributedTo: actorJSON.attributedTo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +364,14 @@ async function refreshActorIfNeeded (actor: ActorModel): Promise<ActorModel> {
|
|||
|
||||
try {
|
||||
const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost())
|
||||
const result = await fetchRemoteActor(actorUrl)
|
||||
const { result, statusCode } = await fetchRemoteActor(actorUrl)
|
||||
|
||||
if (statusCode === 404) {
|
||||
logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
|
||||
actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy()
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
logger.warn('Cannot fetch remote actor in refresh actor.')
|
||||
return actor
|
||||
|
|
|
@ -325,15 +325,13 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
|
|||
},
|
||||
include: [
|
||||
{
|
||||
attributes: {
|
||||
exclude: unusedActorAttributesForAPI
|
||||
},
|
||||
model: ActorModel,
|
||||
attributes: [ 'id' ],
|
||||
model: ActorModel.unscoped(),
|
||||
as: 'ActorFollowing',
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
model: VideoChannelModel,
|
||||
model: VideoChannelModel.unscoped(),
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
|
@ -344,7 +342,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
|
|||
required: true
|
||||
},
|
||||
{
|
||||
model: AccountModel,
|
||||
model: AccountModel.unscoped(),
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
|
|
|
@ -50,7 +50,9 @@ export const unusedActorAttributesForAPI = [
|
|||
'sharedInboxUrl',
|
||||
'followersUrl',
|
||||
'followingUrl',
|
||||
'url'
|
||||
'url',
|
||||
'createdAt',
|
||||
'updatedAt'
|
||||
]
|
||||
|
||||
@DefaultScope({
|
||||
|
|
|
@ -6,7 +6,6 @@ import { flushTests, immutableAssign, killallServers, makeGetRequest, runServer,
|
|||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
||||
|
||||
describe('Test videos API validator', function () {
|
||||
const path = '/api/v1/search/videos/'
|
||||
let server: ServerInfo
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
@ -20,6 +19,8 @@ describe('Test videos API validator', function () {
|
|||
})
|
||||
|
||||
describe('When searching videos', function () {
|
||||
const path = '/api/v1/search/videos/'
|
||||
|
||||
const query = {
|
||||
search: 'coucou'
|
||||
}
|
||||
|
@ -111,6 +112,30 @@ describe('Test videos API validator', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('When searching video channels', function () {
|
||||
const path = '/api/v1/search/video-channels/'
|
||||
|
||||
const query = {
|
||||
search: 'coucou'
|
||||
}
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query, statusCodeExpected: 200 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
killallServers([ server ])
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
import './search-activitypub-video-channels'
|
||||
import './search-activitypub-videos'
|
||||
import './search-videos'
|
||||
|
|
176
server/tests/api/search/search-activitypub-video-channels.ts
Normal file
176
server/tests/api/search/search-activitypub-video-channels.ts
Normal file
|
@ -0,0 +1,176 @@
|
|||
/* tslint:disable:no-unused-expression */
|
||||
|
||||
import * as chai from 'chai'
|
||||
import 'mocha'
|
||||
import {
|
||||
addVideoChannel,
|
||||
createUser,
|
||||
deleteVideoChannel,
|
||||
flushAndRunMultipleServers,
|
||||
flushTests,
|
||||
getVideoChannelsList,
|
||||
killallServers,
|
||||
ServerInfo,
|
||||
setAccessTokensToServers,
|
||||
updateMyUser,
|
||||
updateVideoChannel,
|
||||
uploadVideo,
|
||||
userLogin,
|
||||
wait
|
||||
} from '../../utils'
|
||||
import { waitJobs } from '../../utils/server/jobs'
|
||||
import { VideoChannel } from '../../../../shared/models/videos'
|
||||
import { searchVideoChannel } from '../../utils/search/video-channels'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
describe('Test a ActivityPub video channels search', function () {
|
||||
let servers: ServerInfo[]
|
||||
let userServer2Token: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
await flushTests()
|
||||
|
||||
servers = await flushAndRunMultipleServers(2)
|
||||
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
{
|
||||
await createUser(servers[0].url, servers[0].accessToken, 'user1_server1', 'password')
|
||||
const channel = {
|
||||
name: 'channel1_server1',
|
||||
displayName: 'Channel 1 server 1'
|
||||
}
|
||||
await addVideoChannel(servers[0].url, servers[0].accessToken, channel)
|
||||
}
|
||||
|
||||
{
|
||||
const user = { username: 'user1_server2', password: 'password' }
|
||||
await createUser(servers[1].url, servers[1].accessToken, user.username, user.password)
|
||||
userServer2Token = await userLogin(servers[1], user)
|
||||
|
||||
const channel = {
|
||||
name: 'channel1_server2',
|
||||
displayName: 'Channel 1 server 2'
|
||||
}
|
||||
const resChannel = await addVideoChannel(servers[1].url, userServer2Token, channel)
|
||||
const channelId = resChannel.body.videoChannel.id
|
||||
|
||||
await uploadVideo(servers[1].url, userServer2Token, { name: 'video 1 server 2', channelId })
|
||||
await uploadVideo(servers[1].url, userServer2Token, { name: 'video 2 server 2', channelId })
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should not find a remote video channel', async function () {
|
||||
{
|
||||
const search = 'http://localhost:9002/video-channels/channel1_server3'
|
||||
const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
|
||||
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data).to.have.lengthOf(0)
|
||||
}
|
||||
|
||||
{
|
||||
// Without token
|
||||
const search = 'http://localhost:9002/video-channels/channel1_server2'
|
||||
const res = await searchVideoChannel(servers[0].url, search)
|
||||
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data).to.have.lengthOf(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should search a local video channel', async function () {
|
||||
const searches = [
|
||||
'http://localhost:9001/video-channels/channel1_server1',
|
||||
'channel1_server1@localhost:9001'
|
||||
]
|
||||
|
||||
for (const search of searches) {
|
||||
const res = await searchVideoChannel(servers[ 0 ].url, search)
|
||||
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data).to.have.lengthOf(1)
|
||||
expect(res.body.data[ 0 ].name).to.equal('channel1_server1')
|
||||
expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 1')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should search a remote video channel with URL or handle', async function () {
|
||||
const searches = [
|
||||
'http://localhost:9002/video-channels/channel1_server2',
|
||||
'channel1_server2@localhost:9002'
|
||||
]
|
||||
|
||||
for (const search of searches) {
|
||||
const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
|
||||
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data).to.have.lengthOf(1)
|
||||
expect(res.body.data[ 0 ].name).to.equal('channel1_server2')
|
||||
expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 2')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should not list this remote video channel', async function () {
|
||||
const res = await getVideoChannelsList(servers[0].url, 0, 5)
|
||||
expect(res.body.total).to.equal(3)
|
||||
expect(res.body.data).to.have.lengthOf(3)
|
||||
expect(res.body.data[0].name).to.equal('channel1_server1')
|
||||
expect(res.body.data[1].name).to.equal('user1_server1_channel')
|
||||
expect(res.body.data[2].name).to.equal('root_channel')
|
||||
})
|
||||
|
||||
it('Should update video channel of server 2, and refresh it on server 1', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await updateVideoChannel(servers[1].url, userServer2Token, 'channel1_server2', { displayName: 'channel updated' })
|
||||
await updateMyUser({ url: servers[1].url, accessToken: userServer2Token, displayName: 'user updated' })
|
||||
|
||||
await waitJobs(servers)
|
||||
// Expire video channel
|
||||
await wait(10000)
|
||||
|
||||
const search = 'http://localhost:9002/video-channels/channel1_server2'
|
||||
const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data).to.have.lengthOf(1)
|
||||
|
||||
const videoChannel: VideoChannel = res.body.data[0]
|
||||
expect(videoChannel.displayName).to.equal('channel updated')
|
||||
|
||||
// We don't return the owner account for now
|
||||
// expect(videoChannel.ownerAccount.displayName).to.equal('user updated')
|
||||
})
|
||||
|
||||
it('Should delete video channel of server 2, and delete it on server 1', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await deleteVideoChannel(servers[1].url, userServer2Token, 'channel1_server2')
|
||||
|
||||
await waitJobs(servers)
|
||||
// Expire video
|
||||
await wait(10000)
|
||||
|
||||
const res = await searchVideoChannel(servers[0].url, 'http://localhost:9002/video-channels/channel1_server2', servers[0].accessToken)
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.have.lengthOf(0)
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
killallServers(servers)
|
||||
|
||||
// Keep the logs if the test failed
|
||||
if (this['ok']) {
|
||||
await flushTests()
|
||||
}
|
||||
})
|
||||
})
|
|
@ -59,6 +59,7 @@ describe('Test a ActivityPub videos search', function () {
|
|||
}
|
||||
|
||||
{
|
||||
// Without token
|
||||
const res = await searchVideo(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID)
|
||||
|
||||
expect(res.body.total).to.equal(0)
|
||||
|
|
22
server/tests/utils/search/video-channels.ts
Normal file
22
server/tests/utils/search/video-channels.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { makeGetRequest } from '../requests/requests'
|
||||
|
||||
function searchVideoChannel (url: string, search: string, token?: string, statusCodeExpected = 200) {
|
||||
const path = '/api/v1/search/video-channels'
|
||||
|
||||
return makeGetRequest({
|
||||
url,
|
||||
path,
|
||||
query: {
|
||||
sort: '-createdAt',
|
||||
search
|
||||
},
|
||||
token,
|
||||
statusCodeExpected
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
searchVideoChannel
|
||||
}
|
|
@ -54,12 +54,12 @@ function addVideoChannel (
|
|||
function updateVideoChannel (
|
||||
url: string,
|
||||
token: string,
|
||||
channelId: number | string,
|
||||
channelName: string,
|
||||
attributes: VideoChannelUpdate,
|
||||
expectedStatus = 204
|
||||
) {
|
||||
const body = {}
|
||||
const path = '/api/v1/video-channels/' + channelId
|
||||
const path = '/api/v1/video-channels/' + channelName
|
||||
|
||||
if (attributes.displayName) body['displayName'] = attributes.displayName
|
||||
if (attributes.description) body['description'] = attributes.description
|
||||
|
@ -73,8 +73,8 @@ function updateVideoChannel (
|
|||
.expect(expectedStatus)
|
||||
}
|
||||
|
||||
function deleteVideoChannel (url: string, token: string, channelId: number | string, expectedStatus = 204) {
|
||||
const path = '/api/v1/video-channels/' + channelId
|
||||
function deleteVideoChannel (url: string, token: string, channelName: string, expectedStatus = 204) {
|
||||
const path = '/api/v1/video-channels/' + channelName
|
||||
|
||||
return request(url)
|
||||
.delete(path)
|
||||
|
@ -83,8 +83,8 @@ function deleteVideoChannel (url: string, token: string, channelId: number | str
|
|||
.expect(expectedStatus)
|
||||
}
|
||||
|
||||
function getVideoChannel (url: string, channelId: number | string) {
|
||||
const path = '/api/v1/video-channels/' + channelId
|
||||
function getVideoChannel (url: string, channelName: string) {
|
||||
const path = '/api/v1/video-channels/' + channelName
|
||||
|
||||
return request(url)
|
||||
.get(path)
|
||||
|
|
Loading…
Reference in a new issue