Add ability to set a name to a channel

This commit is contained in:
Chocobozzz 2018-08-17 15:45:42 +02:00
parent 965c4b22d0
commit 8a19bee1a1
45 changed files with 321 additions and 184 deletions

View File

@ -1,6 +1,6 @@
<div *ngIf="account" class="row"> <div *ngIf="account" class="row">
<a <a
*ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.uuid ]" *ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.name ]"
class="video-channel" i18n-title title="See this video channel" class="video-channel" i18n-title title="See this video channel"
> >
<img [src]="videoChannel.avatarUrl" alt="Avatar" /> <img [src]="videoChannel.avatarUrl" alt="Avatar" />

View File

@ -2,10 +2,10 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { Account } from '@app/shared/account/account.model' import { Account } from '@app/shared/account/account.model'
import { AccountService } from '@app/shared/account/account.service' import { AccountService } from '@app/shared/account/account.service'
import { VideoChannel } from '../../../../../shared/models/videos'
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
import { flatMap, map, tap } from 'rxjs/operators' import { flatMap, map, tap } from 'rxjs/operators'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
@Component({ @Component({
selector: 'my-account-video-channels', selector: 'my-account-video-channels',

View File

@ -29,8 +29,13 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
super() super()
} }
get instanceHost () {
return window.location.host
}
ngOnInit () { ngOnInit () {
this.buildForm({ this.buildForm({
name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME,
'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT
@ -42,6 +47,7 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
const body = this.form.value const body = this.form.value
const videoChannelCreate: VideoChannelCreate = { const videoChannelCreate: VideoChannelCreate = {
name: body.name,
displayName: body['display-name'], displayName: body['display-name'],
description: body.description || null, description: body.description || null,
support: body.support || null support: body.support || null

View File

@ -8,6 +8,22 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> <form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
<div class="form-group" *ngIf="isCreation() === true">
<label i18n for="name">Name</label>
<div class="input-group">
<input
type="text" id="name" i18n-placeholder placeholder="Example: my_channel"
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }"
>
<div class="input-group-append">
<span class="input-group-text">@{{ instanceHost }}</span>
</div>
</div>
<div *ngIf="formErrors['name']" class="form-error">
{{ formErrors['name'] }}
</div>
</div>
<div class="form-group"> <div class="form-group">
<label i18n for="display-name">Display name</label> <label i18n for="display-name">Display name</label>
<input <input

View File

@ -10,10 +10,19 @@ my-actor-avatar-info {
margin-bottom: 20px; margin-bottom: 20px;
} }
.input-group {
@include peertube-input-group(340px);
}
input[type=text] { input[type=text] {
@include peertube-input-text(340px); @include peertube-input-text(340px);
display: block; display: block;
&#name {
width: auto;
flex-grow: 1;
}
} }
textarea { textarea {

View File

@ -7,15 +7,14 @@
<div class="video-channels"> <div class="video-channels">
<div *ngFor="let videoChannel of videoChannels" class="video-channel"> <div *ngFor="let videoChannel of videoChannels" class="video-channel">
<a [routerLink]="[ '/video-channels', videoChannel.uuid ]"> <a [routerLink]="[ '/video-channels', videoChannel.name ]">
<img [src]="videoChannel.avatarUrl" alt="Avatar" /> <img [src]="videoChannel.avatarUrl" alt="Avatar" />
</a> </a>
<div class="video-channel-info"> <div class="video-channel-info">
<a [routerLink]="[ '/video-channels', videoChannel.uuid ]" class="video-channel-names" i18n-title title="Go to the channel"> <a [routerLink]="[ '/video-channels', videoChannel.name ]" class="video-channel-names" i18n-title title="Go to the channel">
<div class="video-channel-display-name">{{ videoChannel.displayName }}</div> <div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
<!-- Hide the name for now, because it's an UUID not very friendly --> <div class="video-channel-name">{{ videoChannel.name }}</div>
<!--<div class="video-channel-name">{{ videoChannel.name }}</div>-->
</a> </a>
<div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div> <div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
@ -24,7 +23,7 @@
<div class="video-channel-buttons"> <div class="video-channel-buttons">
<my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button> <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
<my-edit-button [routerLink]="[ 'update', videoChannel.uuid ]"></my-edit-button> <my-edit-button [routerLink]="[ 'update', videoChannel.name ]"></my-edit-button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -30,7 +30,9 @@
a.video-channel-names { a.video-channel-names {
@include disable-default-a-behaviour; @include disable-default-a-behaviour;
width: fit-content;
display: flex; display: flex;
align-items: baseline;
color: #000; color: #000;
.video-channel-display-name { .video-channel-display-name {
@ -41,6 +43,7 @@
.video-channel-name { .video-channel-name {
font-size: 14px; font-size: 14px;
color: #777272; color: #777272;
margin-left: 5px;
} }
} }
} }

View File

@ -7,6 +7,7 @@
<div class="actor-info"> <div class="actor-info">
<div class="actor-names"> <div class="actor-names">
<div class="actor-display-name">{{ videoChannel.displayName }}</div> <div class="actor-display-name">{{ videoChannel.displayName }}</div>
<div class="actor-name">{{ videoChannel.nameWithHost }}</div>
</div> </div>
<div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div> <div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>

View File

@ -5,11 +5,27 @@ import { BuildFormValidator } from '@app/shared'
@Injectable() @Injectable()
export class VideoChannelValidatorsService { export class VideoChannelValidatorsService {
readonly VIDEO_CHANNEL_NAME: BuildFormValidator
readonly VIDEO_CHANNEL_DISPLAY_NAME: BuildFormValidator readonly VIDEO_CHANNEL_DISPLAY_NAME: BuildFormValidator
readonly VIDEO_CHANNEL_DESCRIPTION: BuildFormValidator readonly VIDEO_CHANNEL_DESCRIPTION: BuildFormValidator
readonly VIDEO_CHANNEL_SUPPORT: BuildFormValidator readonly VIDEO_CHANNEL_SUPPORT: BuildFormValidator
constructor (private i18n: I18n) { constructor (private i18n: I18n) {
this.VIDEO_CHANNEL_NAME = {
VALIDATORS: [
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-z0-9._]+$/)
],
MESSAGES: {
'required': this.i18n('Name is required.'),
'minlength': this.i18n('Name must be at least 3 characters long.'),
'maxlength': this.i18n('Name cannot be more than 20 characters long.'),
'pattern': this.i18n('Name should be only lowercase alphanumeric characters.')
}
}
this.VIDEO_CHANNEL_DISPLAY_NAME = { this.VIDEO_CHANNEL_DISPLAY_NAME = {
VALIDATORS: [ VALIDATORS: [
Validators.required, Validators.required,

View File

@ -7,6 +7,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
description: string description: string
support: string support: string
isLocal: boolean isLocal: boolean
nameWithHost: string
ownerAccount?: Account ownerAccount?: Account
ownerBy?: string ownerBy?: string
ownerAvatarUrl?: string ownerAvatarUrl?: string
@ -18,6 +19,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
this.description = hash.description this.description = hash.description
this.support = hash.support this.support = hash.support
this.isLocal = hash.isLocal this.isLocal = hash.isLocal
this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
if (hash.ownerAccount) { if (hash.ownerAccount) {
this.ownerAccount = hash.ownerAccount this.ownerAccount = hash.ownerAccount

View File

@ -22,8 +22,8 @@ export class VideoChannelService {
private restExtractor: RestExtractor private restExtractor: RestExtractor
) {} ) {}
getVideoChannel (videoChannelUUID: string) { getVideoChannel (videoChannelName: string) {
return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID) return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelName)
.pipe( .pipe(
map(videoChannelHash => new VideoChannel(videoChannelHash)), map(videoChannelHash => new VideoChannel(videoChannelHash)),
tap(videoChannel => this.videoChannelLoaded.next(videoChannel)), tap(videoChannel => this.videoChannelLoaded.next(videoChannel)),

View File

@ -150,7 +150,7 @@ export class VideoService {
params = this.restService.addRestGetParams(params, pagination, sort) params = this.restService.addRestGetParams(params, pagination, sort)
return this.authHttp return this.authHttp
.get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params }) .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.name + '/videos', { params })
.pipe( .pipe(
switchMap(res => this.extractVideos(res)), switchMap(res => this.extractVideos(res)),
catchError(err => this.restExtractor.handleError(err)) catchError(err => this.restExtractor.handleError(err))

View File

@ -23,10 +23,17 @@
<form role="form" (ngSubmit)="signup()" [formGroup]="form"> <form role="form" (ngSubmit)="signup()" [formGroup]="form">
<div class="form-group"> <div class="form-group">
<label for="username" i18n>Username</label> <label for="username" i18n>Username</label>
<div class="input-group">
<input <input
type="text" id="username" i18n-placeholder placeholder="Username" type="text" id="username" i18n-placeholder placeholder="Example: neil_amstrong"
formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }" formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
> >
<div class="input-group-append">
<span class="input-group-text">@{{ instanceHost }}</span>
</div>
</div>
<div *ngIf="formErrors.username" class="form-error"> <div *ngIf="formErrors.username" class="form-error">
{{ formErrors.username }} {{ formErrors.username }}
</div> </div>

View File

@ -14,9 +14,18 @@
margin: 30px 0; margin: 30px 0;
} }
.input-group {
@include peertube-input-group(340px);
}
input:not([type=submit]) { input:not([type=submit]) {
@include peertube-input-text(340px); @include peertube-input-text(340px);
display: block; display: block;
&#username {
width: auto;
flex-grow: 1;
}
} }
input[type=submit] { input[type=submit] {

View File

@ -34,6 +34,10 @@ export class SignupComponent extends FormReactive implements OnInit {
return this.serverService.getConfig().user.videoQuota return this.serverService.getConfig().user.videoQuota
} }
get instanceHost () {
return window.location.host
}
ngOnInit () { ngOnInit () {
this.buildForm({ this.buildForm({
username: this.userValidatorsService.USER_USERNAME, username: this.userValidatorsService.USER_USERNAME,

View File

@ -37,7 +37,7 @@
</div> </div>
<div class="video-info-channel"> <div class="video-info-channel">
<a [routerLink]="[ '/video-channels', video.channel.uuid ]" i18n-title title="Go the channel page"> <a [routerLink]="[ '/video-channels', video.channel.name ]" i18n-title title="Go the channel page">
{{ video.channel.displayName }} {{ video.channel.displayName }}
<img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" /> <img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" />

View File

@ -36,9 +36,16 @@
border-radius: 3px; border-radius: 3px;
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
}
&::placeholder { @mixin peertube-input-group($width) {
color: #585858; width: $width;
height: $button-height;
padding-top: 0;
padding-bottom: 0;
.input-group-text{
font-size: 14px;
} }
} }

View File

@ -6,8 +6,8 @@ import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../initializers'
import { buildVideoAnnounce } from '../../lib/activitypub/send' import { buildVideoAnnounce } from '../../lib/activitypub/send'
import { audiencify, getAudience } from '../../lib/activitypub/audience' import { audiencify, getAudience } from '../../lib/activitypub/audience'
import { createActivityData } from '../../lib/activitypub/send/send-create' import { createActivityData } from '../../lib/activitypub/send/send-create'
import { asyncMiddleware, executeIfActivityPub, localAccountValidator } from '../../middlewares' import { asyncMiddleware, executeIfActivityPub, localAccountValidator, localVideoChannelValidator } from '../../middlewares'
import { videoChannelsGetValidator, videosGetValidator, videosShareValidator } from '../../middlewares/validators' import { videosGetValidator, videosShareValidator } from '../../middlewares/validators'
import { videoCommentGetValidator } from '../../middlewares/validators/video-comments' import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
import { AccountModel } from '../../models/account/account' import { AccountModel } from '../../models/account/account'
import { ActorModel } from '../../models/activitypub/actor' import { ActorModel } from '../../models/activitypub/actor'
@ -80,16 +80,16 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
executeIfActivityPub(asyncMiddleware(videoCommentController)) executeIfActivityPub(asyncMiddleware(videoCommentController))
) )
activityPubClientRouter.get('/video-channels/:id', activityPubClientRouter.get('/video-channels/:name',
executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)), executeIfActivityPub(asyncMiddleware(localVideoChannelValidator)),
executeIfActivityPub(asyncMiddleware(videoChannelController)) executeIfActivityPub(asyncMiddleware(videoChannelController))
) )
activityPubClientRouter.get('/video-channels/:id/followers', activityPubClientRouter.get('/video-channels/:name/followers',
executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)), executeIfActivityPub(asyncMiddleware(localVideoChannelValidator)),
executeIfActivityPub(asyncMiddleware(videoChannelFollowersController)) executeIfActivityPub(asyncMiddleware(videoChannelFollowersController))
) )
activityPubClientRouter.get('/video-channels/:id/following', activityPubClientRouter.get('/video-channels/:name/following',
executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)), executeIfActivityPub(asyncMiddleware(localVideoChannelValidator)),
executeIfActivityPub(asyncMiddleware(videoChannelFollowingController)) executeIfActivityPub(asyncMiddleware(videoChannelFollowingController))
) )

View File

@ -78,7 +78,7 @@ async function listAccountVideos (req: express.Request, res: express.Response, n
start: req.query.start, start: req.query.start,
count: req.query.count, count: req.query.count,
sort: req.query.sort, sort: req.query.sort,
includeLocalVideos: false, includeLocalVideos: true,
categoryOneOf: req.query.categoryOneOf, categoryOneOf: req.query.categoryOneOf,
licenceOneOf: req.query.licenceOneOf, licenceOneOf: req.query.licenceOneOf,
languageOneOf: req.query.languageOneOf, languageOneOf: req.query.languageOneOf,

View File

@ -10,13 +10,12 @@ import {
setDefaultPagination, setDefaultPagination,
setDefaultSort, setDefaultSort,
videoChannelsAddValidator, videoChannelsAddValidator,
videoChannelsGetValidator,
videoChannelsRemoveValidator, videoChannelsRemoveValidator,
videoChannelsSortValidator, videoChannelsSortValidator,
videoChannelsUpdateValidator videoChannelsUpdateValidator
} from '../../middlewares' } from '../../middlewares'
import { VideoChannelModel } from '../../models/video/video-channel' import { VideoChannelModel } from '../../models/video/video-channel'
import { videosSortValidator } from '../../middlewares/validators' import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators'
import { sendUpdateActor } from '../../lib/activitypub/send' import { sendUpdateActor } from '../../lib/activitypub/send'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
import { createVideoChannel } from '../../lib/video-channel' import { createVideoChannel } from '../../lib/video-channel'
@ -50,7 +49,7 @@ videoChannelRouter.post('/',
asyncRetryTransactionMiddleware(addVideoChannel) asyncRetryTransactionMiddleware(addVideoChannel)
) )
videoChannelRouter.post('/:id/avatar/pick', videoChannelRouter.post('/:nameWithHost/avatar/pick',
authenticate, authenticate,
reqAvatarFile, reqAvatarFile,
// Check the rights // Check the rights
@ -59,25 +58,25 @@ videoChannelRouter.post('/:id/avatar/pick',
asyncMiddleware(updateVideoChannelAvatar) asyncMiddleware(updateVideoChannelAvatar)
) )
videoChannelRouter.put('/:id', videoChannelRouter.put('/:nameWithHost',
authenticate, authenticate,
asyncMiddleware(videoChannelsUpdateValidator), asyncMiddleware(videoChannelsUpdateValidator),
asyncRetryTransactionMiddleware(updateVideoChannel) asyncRetryTransactionMiddleware(updateVideoChannel)
) )
videoChannelRouter.delete('/:id', videoChannelRouter.delete('/:nameWithHost',
authenticate, authenticate,
asyncMiddleware(videoChannelsRemoveValidator), asyncMiddleware(videoChannelsRemoveValidator),
asyncRetryTransactionMiddleware(removeVideoChannel) asyncRetryTransactionMiddleware(removeVideoChannel)
) )
videoChannelRouter.get('/:id', videoChannelRouter.get('/:nameWithHost',
asyncMiddleware(videoChannelsGetValidator), asyncMiddleware(videoChannelsNameWithHostValidator),
asyncMiddleware(getVideoChannel) asyncMiddleware(getVideoChannel)
) )
videoChannelRouter.get('/:id/videos', videoChannelRouter.get('/:nameWithHost/videos',
asyncMiddleware(videoChannelsGetValidator), asyncMiddleware(videoChannelsNameWithHostValidator),
paginationValidator, paginationValidator,
videosSortValidator, videosSortValidator,
setDefaultSort, setDefaultSort,
@ -215,7 +214,7 @@ async function listVideoChannelVideos (req: express.Request, res: express.Respon
start: req.query.start, start: req.query.start,
count: req.query.count, count: req.query.count,
sort: req.query.sort, sort: req.query.sort,
includeLocalVideos: false, includeLocalVideos: true,
categoryOneOf: req.query.categoryOneOf, categoryOneOf: req.query.categoryOneOf,
licenceOneOf: req.query.licenceOneOf, licenceOneOf: req.query.licenceOneOf,
languageOneOf: req.query.languageOneOf, languageOneOf: req.query.languageOneOf,

View File

@ -42,7 +42,7 @@ function isAccountNameWithHostExist (nameWithDomain: string, res: Response, send
let promise: Bluebird<AccountModel> let promise: Bluebird<AccountModel>
if (!host || host === CONFIG.WEBSERVER.HOST) promise = AccountModel.loadLocalByName(accountName) if (!host || host === CONFIG.WEBSERVER.HOST) promise = AccountModel.loadLocalByName(accountName)
else promise = AccountModel.loadLocalByNameAndHost(accountName, host) else promise = AccountModel.loadByNameAndHost(accountName, host)
return isAccountExist(promise, res, sendNotFound) return isAccountExist(promise, res, sendNotFound)
} }

View File

@ -27,7 +27,7 @@ function isActorPublicKeyValid (publicKey: string) {
validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY) validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
} }
const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') const actorNameRegExp = new RegExp('^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_]+$')
function isActorPreferredUsernameValid (preferredUsername: string) { function isActorPreferredUsernameValid (preferredUsername: string) {
return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp) return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
} }

View File

@ -2,10 +2,9 @@ import * as express from 'express'
import 'express-validator' import 'express-validator'
import 'multer' import 'multer'
import * as validator from 'validator' import * as validator from 'validator'
import { CONSTRAINTS_FIELDS } from '../../initializers' import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
import { VideoChannelModel } from '../../models/video/video-channel' import { VideoChannelModel } from '../../models/video/video-channel'
import { exists } from './misc' import { exists } from './misc'
import { Response } from 'express'
const VIDEO_CHANNELS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_CHANNELS const VIDEO_CHANNELS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_CHANNELS
@ -21,13 +20,13 @@ function isVideoChannelSupportValid (value: string) {
return value === null || (exists(value) && validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.SUPPORT)) return value === null || (exists(value) && validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.SUPPORT))
} }
async function isLocalVideoChannelNameExist (name: string, res: Response) { async function isLocalVideoChannelNameExist (name: string, res: express.Response) {
const videoChannel = await VideoChannelModel.loadLocalByName(name) const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name)
return processVideoChannelExist(videoChannel, res) return processVideoChannelExist(videoChannel, res)
} }
async function isVideoChannelExist (id: string, res: express.Response) { async function isVideoChannelIdExist (id: string, res: express.Response) {
let videoChannel: VideoChannelModel let videoChannel: VideoChannelModel
if (validator.isInt(id)) { if (validator.isInt(id)) {
videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
@ -38,14 +37,25 @@ async function isVideoChannelExist (id: string, res: express.Response) {
return processVideoChannelExist(videoChannel, res) return processVideoChannelExist(videoChannel, res)
} }
async function isVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) {
const [ name, host ] = nameWithDomain.split('@')
let videoChannel: VideoChannelModel
if (!host || host === CONFIG.WEBSERVER.HOST) videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name)
else videoChannel = await VideoChannelModel.loadByNameAndHostAndPopulateAccount(name, host)
return processVideoChannelExist(videoChannel, res)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
isVideoChannelNameWithHostExist,
isLocalVideoChannelNameExist, isLocalVideoChannelNameExist,
isVideoChannelDescriptionValid, isVideoChannelDescriptionValid,
isVideoChannelNameValid, isVideoChannelNameValid,
isVideoChannelSupportValid, isVideoChannelSupportValid,
isVideoChannelExist isVideoChannelIdExist
} }
function processVideoChannelExist (videoChannel: VideoChannelModel, res: express.Response) { function processVideoChannelExist (videoChannel: VideoChannelModel, res: express.Response) {

View File

@ -13,8 +13,8 @@ function getVideoCommentActivityPubUrl (video: VideoModel, videoComment: VideoCo
return CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id return CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id
} }
function getVideoChannelActivityPubUrl (videoChannelUUID: string) { function getVideoChannelActivityPubUrl (videoChannelName: string) {
return CONFIG.WEBSERVER.URL + '/video-channels/' + videoChannelUUID return CONFIG.WEBSERVER.URL + '/video-channels/' + videoChannelName
} }
function getAccountActivityPubUrl (accountName: string) { function getAccountActivityPubUrl (accountName: string) {

View File

@ -1,4 +1,5 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
import * as uuidv4 from 'uuid/v4'
import { ActivityPubActorType } from '../../shared/models/activitypub' import { ActivityPubActorType } from '../../shared/models/activitypub'
import { sequelizeTypescript, SERVER_ACTOR_NAME } from '../initializers' import { sequelizeTypescript, SERVER_ACTOR_NAME } from '../initializers'
import { AccountModel } from '../models/account/account' import { AccountModel } from '../models/account/account'
@ -7,6 +8,7 @@ import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from
import { createVideoChannel } from './video-channel' import { createVideoChannel } from './video-channel'
import { VideoChannelModel } from '../models/video/video-channel' import { VideoChannelModel } from '../models/video/video-channel'
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model' import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
import { ActorModel } from '../models/activitypub/actor'
async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) { async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) {
const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
@ -19,8 +21,15 @@ async function createUserAccountAndChannel (userToCreate: UserModel, validateUse
const accountCreated = await createLocalAccountWithoutKeys(userToCreate.username, userToCreate.id, null, t) const accountCreated = await createLocalAccountWithoutKeys(userToCreate.username, userToCreate.id, null, t)
userCreated.Account = accountCreated userCreated.Account = accountCreated
const videoChannelDisplayName = `Default ${userCreated.username} channel` let channelName = userCreated.username + '_channel'
// Conflict, generate uuid instead
const actor = await ActorModel.loadLocalByName(channelName)
if (actor) channelName = uuidv4()
const videoChannelDisplayName = `Main ${userCreated.username} channel`
const videoChannelInfo = { const videoChannelInfo = {
name: channelName,
displayName: videoChannelDisplayName displayName: videoChannelDisplayName
} }
const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t) const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)

View File

@ -7,9 +7,8 @@ import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub
async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) {
const uuid = uuidv4() const uuid = uuidv4()
const url = getVideoChannelActivityPubUrl(uuid) const url = getVideoChannelActivityPubUrl(videoChannelInfo.name)
// We use the name as uuid const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid)
const actorInstance = buildActorInstance('Group', url, uuid, uuid)
const actorInstanceCreated = await actorInstance.save({ transaction: t }) const actorInstanceCreated = await actorInstance.save({ transaction: t })

View File

@ -1,13 +1,13 @@
import * as express from 'express' import * as express from 'express'
import { param, query } from 'express-validator/check' import { param, query } from 'express-validator/check'
import { isAccountIdExist, isAccountNameValid } from '../../helpers/custom-validators/accounts' import { isAccountIdExist, isAccountNameValid, isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts'
import { join } from 'path'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { logger } from '../../helpers/logger' import { logger } from '../../helpers/logger'
import { areValidationErrors } from './utils' import { areValidationErrors } from './utils'
import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' import { isValidRSSFeed } from '../../helpers/custom-validators/feeds'
import { isVideoChannelExist } from '../../helpers/custom-validators/video-channels' import { isVideoChannelIdExist, isVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels'
import { isVideoExist } from '../../helpers/custom-validators/videos' import { isVideoExist } from '../../helpers/custom-validators/videos'
import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
const videoFeedsValidator = [ const videoFeedsValidator = [
param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'),
@ -15,6 +15,7 @@ const videoFeedsValidator = [
query('accountId').optional().custom(isIdOrUUIDValid), query('accountId').optional().custom(isIdOrUUIDValid),
query('accountName').optional().custom(isAccountNameValid), query('accountName').optional().custom(isAccountNameValid),
query('videoChannelId').optional().custom(isIdOrUUIDValid), query('videoChannelId').optional().custom(isIdOrUUIDValid),
query('videoChannelName').optional().custom(isActorPreferredUsernameValid),
async (req: express.Request, res: express.Response, next: express.NextFunction) => { async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking feeds parameters', { parameters: req.query }) logger.debug('Checking feeds parameters', { parameters: req.query })
@ -22,7 +23,9 @@ const videoFeedsValidator = [
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
if (req.query.accountId && !await isAccountIdExist(req.query.accountId, res)) return if (req.query.accountId && !await isAccountIdExist(req.query.accountId, res)) return
if (req.query.videoChannelId && !await isVideoChannelExist(req.query.videoChannelId, res)) return if (req.query.videoChannelName && !await isVideoChannelIdExist(req.query.videoChannelName, res)) return
if (req.query.accountName && !await isAccountNameWithHostExist(req.query.accountName, res)) return
if (req.query.videoChannelName && !await isVideoChannelNameWithHostExist(req.query.videoChannelName, res)) return
return next() return next()
} }

View File

@ -2,18 +2,18 @@ import * as express from 'express'
import { body, param } from 'express-validator/check' import { body, param } from 'express-validator/check'
import { UserRight } from '../../../shared' import { UserRight } from '../../../shared'
import { isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' import { isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { import {
isLocalVideoChannelNameExist, isLocalVideoChannelNameExist,
isVideoChannelDescriptionValid, isVideoChannelDescriptionValid,
isVideoChannelExist,
isVideoChannelNameValid, isVideoChannelNameValid,
isVideoChannelNameWithHostExist,
isVideoChannelSupportValid isVideoChannelSupportValid
} from '../../helpers/custom-validators/video-channels' } from '../../helpers/custom-validators/video-channels'
import { logger } from '../../helpers/logger' import { logger } from '../../helpers/logger'
import { UserModel } from '../../models/account/user' import { UserModel } from '../../models/account/user'
import { VideoChannelModel } from '../../models/video/video-channel' import { VideoChannelModel } from '../../models/video/video-channel'
import { areValidationErrors } from './utils' import { areValidationErrors } from './utils'
import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
const listVideoAccountChannelsValidator = [ const listVideoAccountChannelsValidator = [
param('accountName').exists().withMessage('Should have a valid account name'), param('accountName').exists().withMessage('Should have a valid account name'),
@ -29,6 +29,7 @@ const listVideoAccountChannelsValidator = [
] ]
const videoChannelsAddValidator = [ const videoChannelsAddValidator = [
body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
body('displayName').custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), body('displayName').custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
@ -43,7 +44,7 @@ const videoChannelsAddValidator = [
] ]
const videoChannelsUpdateValidator = [ const videoChannelsUpdateValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), param('nameWithHost').exists().withMessage('Should have an video channel name with host'),
body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
@ -52,7 +53,7 @@ const videoChannelsUpdateValidator = [
logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
if (!await isVideoChannelExist(req.params.id, res)) return if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return
// We need to make additional checks // We need to make additional checks
if (res.locals.videoChannel.Actor.isOwned() === false) { if (res.locals.videoChannel.Actor.isOwned() === false) {
@ -72,13 +73,13 @@ const videoChannelsUpdateValidator = [
] ]
const videoChannelsRemoveValidator = [ const videoChannelsRemoveValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), param('nameWithHost').exists().withMessage('Should have an video channel name with host'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => { async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params })
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
if (!await isVideoChannelExist(req.params.id, res)) return if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return
if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return
if (!await checkVideoChannelIsNotTheLastOne(res)) return if (!await checkVideoChannelIsNotTheLastOne(res)) return
@ -87,15 +88,15 @@ const videoChannelsRemoveValidator = [
} }
] ]
const videoChannelsGetValidator = [ const videoChannelsNameWithHostValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), param('nameWithHost').exists().withMessage('Should have an video channel name with host'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => { async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoChannelsGet parameters', { parameters: req.params }) logger.debug('Checking videoChannelsNameWithHostValidator parameters', { parameters: req.params })
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
if (!await isVideoChannelExist(req.params.id, res)) return if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return
return next() return next()
} }
@ -121,7 +122,7 @@ export {
videoChannelsAddValidator, videoChannelsAddValidator,
videoChannelsUpdateValidator, videoChannelsUpdateValidator,
videoChannelsRemoveValidator, videoChannelsRemoveValidator,
videoChannelsGetValidator, videoChannelsNameWithHostValidator,
localVideoChannelValidator localVideoChannelValidator
} }

View File

@ -194,7 +194,7 @@ export class AccountModel extends Model<AccountModel> {
return AccountModel.findOne(query) return AccountModel.findOne(query)
} }
static loadLocalByNameAndHost (name: string, host: string) { static loadByNameAndHost (name: string, host: string) {
const query = { const query = {
include: [ include: [
{ {

View File

@ -260,12 +260,13 @@ export class ActorModel extends Model<ActorModel> {
return ActorModel.scope(ScopeNames.FULL).findAll(query) return ActorModel.scope(ScopeNames.FULL).findAll(query)
} }
static loadLocalByName (preferredUsername: string) { static loadLocalByName (preferredUsername: string, transaction?: Sequelize.Transaction) {
const query = { const query = {
where: { where: {
preferredUsername, preferredUsername,
serverId: null serverId: null
} },
transaction
} }
return ActorModel.scope(ScopeNames.FULL).findOne(query) return ActorModel.scope(ScopeNames.FULL).findOne(query)

View File

@ -29,6 +29,7 @@ import { getSort, throwIfNotValid } from '../utils'
import { VideoModel } from './video' import { VideoModel } from './video'
import { CONSTRAINTS_FIELDS } from '../../initializers' import { CONSTRAINTS_FIELDS } from '../../initializers'
import { AvatarModel } from '../avatar/avatar' import { AvatarModel } from '../avatar/avatar'
import { ServerModel } from '../server/server'
enum ScopeNames { enum ScopeNames {
WITH_ACCOUNT = 'WITH_ACCOUNT', WITH_ACCOUNT = 'WITH_ACCOUNT',
@ -206,7 +207,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
} }
static loadByIdAndAccount (id: number, accountId: number) { static loadByIdAndAccount (id: number, accountId: number) {
const options = { const query = {
where: { where: {
id, id,
accountId accountId
@ -215,7 +216,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
return VideoChannelModel return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
.findOne(options) .findOne(query)
} }
static loadAndPopulateAccount (id: number) { static loadAndPopulateAccount (id: number) {
@ -225,7 +226,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
} }
static loadByUUIDAndPopulateAccount (uuid: string) { static loadByUUIDAndPopulateAccount (uuid: string) {
const options = { const query = {
include: [ include: [
{ {
model: ActorModel, model: ActorModel,
@ -239,22 +240,10 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
return VideoChannelModel return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
.findOne(options) .findOne(query)
} }
static loadAndPopulateAccountAndVideos (id: number) { static loadLocalByNameAndPopulateAccount (name: string) {
const options = {
include: [
VideoModel
]
}
return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ])
.findById(id, options)
}
static loadLocalByName (name: string) {
const query = { const query = {
include: [ include: [
{ {
@ -268,7 +257,46 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
] ]
} }
return VideoChannelModel.findOne(query) return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
.findOne(query)
}
static loadByNameAndHostAndPopulateAccount (name: string, host: string) {
const query = {
include: [
{
model: ActorModel,
required: true,
where: {
preferredUsername: name
},
include: [
{
model: ServerModel,
required: true,
where: { host }
}
]
}
]
}
return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
.findOne(query)
}
static loadAndPopulateAccountAndVideos (id: number) {
const options = {
include: [
VideoModel
]
}
return VideoChannelModel
.scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ])
.findById(id, options)
} }
toFormattedJSON (): VideoChannel { toFormattedJSON (): VideoChannel {

View File

@ -5,7 +5,6 @@ import 'mocha'
import { import {
createUser, createUser,
flushTests, flushTests,
getMyUserInformation,
killallServers, killallServers,
makeDeleteRequest, makeDeleteRequest,
makeGetRequest, makeGetRequest,
@ -21,7 +20,6 @@ describe('Test user subscriptions API validators', function () {
const path = '/api/v1/users/me/subscriptions' const path = '/api/v1/users/me/subscriptions'
let server: ServerInfo let server: ServerInfo
let userAccessToken = '' let userAccessToken = ''
let userChannelUUID: string
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -40,11 +38,6 @@ describe('Test user subscriptions API validators', function () {
} }
await createUser(server.url, server.accessToken, user.username, user.password) await createUser(server.url, server.accessToken, user.username, user.password)
userAccessToken = await userLogin(server, user) userAccessToken = await userLogin(server, user)
{
const res = await getMyUserInformation(server.url, server.accessToken)
userChannelUUID = res.body.videoChannels[ 0 ].uuid
}
}) })
describe('When listing my subscriptions', function () { describe('When listing my subscriptions', function () {
@ -69,7 +62,7 @@ describe('Test user subscriptions API validators', function () {
}) })
it('Should success with the correct parameters', async function () { it('Should success with the correct parameters', async function () {
await await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path, path,
token: userAccessToken, token: userAccessToken,
@ -102,7 +95,7 @@ describe('Test user subscriptions API validators', function () {
}) })
it('Should success with the correct parameters', async function () { it('Should success with the correct parameters', async function () {
await await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path, path,
token: userAccessToken, token: userAccessToken,
@ -116,7 +109,7 @@ describe('Test user subscriptions API validators', function () {
await makePostBodyRequest({ await makePostBodyRequest({
url: server.url, url: server.url,
path, path,
fields: { uri: userChannelUUID + '@localhost:9001' }, fields: { uri: 'user1_channel@localhost:9001' },
statusCodeExpected: 401 statusCodeExpected: 401
}) })
}) })
@ -152,7 +145,7 @@ describe('Test user subscriptions API validators', function () {
url: server.url, url: server.url,
path, path,
token: server.accessToken, token: server.accessToken,
fields: { uri: userChannelUUID + '@localhost:9001' }, fields: { uri: 'user1_channel@localhost:9001' },
statusCodeExpected: 204 statusCodeExpected: 204
}) })
}) })
@ -162,7 +155,7 @@ describe('Test user subscriptions API validators', function () {
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
await makeDeleteRequest({ await makeDeleteRequest({
url: server.url, url: server.url,
path: path + '/' + userChannelUUID + '@localhost:9001', path: path + '/user1_channel@localhost:9001',
statusCodeExpected: 401 statusCodeExpected: 401
}) })
}) })
@ -202,7 +195,7 @@ describe('Test user subscriptions API validators', function () {
it('Should success with the correct parameters', async function () { it('Should success with the correct parameters', async function () {
await makeDeleteRequest({ await makeDeleteRequest({
url: server.url, url: server.url,
path: path + '/' + userChannelUUID + '@localhost:9001', path: path + '/user1_channel@localhost:9001',
token: server.accessToken, token: server.accessToken,
statusCodeExpected: 204 statusCodeExpected: 204
}) })

View File

@ -31,7 +31,6 @@ describe('Test video channels API validator', function () {
const videoChannelPath = '/api/v1/video-channels' const videoChannelPath = '/api/v1/video-channels'
let server: ServerInfo let server: ServerInfo
let accessTokenUser: string let accessTokenUser: string
let videoChannelUUID: string
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -53,12 +52,6 @@ describe('Test video channels API validator', function () {
await createUser(server.url, server.accessToken, user.username, user.password) await createUser(server.url, server.accessToken, user.username, user.password)
accessTokenUser = await userLogin(server, user) accessTokenUser = await userLogin(server, user)
} }
{
const res = await getMyUserInformation(server.url, server.accessToken)
const user: User = res.body
videoChannelUUID = user.videoChannels[0].uuid
}
}) })
describe('When listing a video channels', function () { describe('When listing a video channels', function () {
@ -83,6 +76,7 @@ describe('Test video channels API validator', function () {
describe('When adding a video channel', function () { describe('When adding a video channel', function () {
const baseCorrectParams = { const baseCorrectParams = {
name: 'super_channel',
displayName: 'hello', displayName: 'hello',
description: 'super description', description: 'super description',
support: 'super support text' support: 'super support text'
@ -103,6 +97,16 @@ describe('Test video channels API validator', function () {
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
}) })
it('Should fail without a name', async function () {
const fields = omit(baseCorrectParams, 'name')
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
})
it('Should fail with a bad name', async function () {
const fields = immutableAssign(baseCorrectParams, { name: 'super name' })
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
})
it('Should fail without a name', async function () { it('Should fail without a name', async function () {
const fields = omit(baseCorrectParams, 'displayName') const fields = omit(baseCorrectParams, 'displayName')
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
@ -142,7 +146,7 @@ describe('Test video channels API validator', function () {
let path: string let path: string
before(async function () { before(async function () {
path = videoChannelPath + '/' + videoChannelUUID path = videoChannelPath + '/super_channel'
}) })
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
@ -195,7 +199,7 @@ describe('Test video channels API validator', function () {
let path: string let path: string
before(async function () { before(async function () {
path = videoChannelPath + '/' + videoChannelUUID path = videoChannelPath + '/super_channel'
}) })
it('Should fail with an incorrect input file', async function () { it('Should fail with an incorrect input file', async function () {
@ -255,18 +259,10 @@ describe('Test video channels API validator', function () {
expect(res.body.data).to.be.an('array') expect(res.body.data).to.be.an('array')
}) })
it('Should fail without a correct uuid', async function () {
await makeGetRequest({
url: server.url,
path: videoChannelPath + '/coucou',
statusCodeExpected: 400
})
})
it('Should return 404 with an incorrect video channel', async function () { it('Should return 404 with an incorrect video channel', async function () {
await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path: videoChannelPath + '/4da6fde3-88f7-4d16-b119-108df5630b06', path: videoChannelPath + '/super_channel2',
statusCodeExpected: 404 statusCodeExpected: 404
}) })
}) })
@ -274,7 +270,7 @@ describe('Test video channels API validator', function () {
it('Should succeed with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path: videoChannelPath + '/' + videoChannelUUID, path: videoChannelPath + '/super_channel',
statusCodeExpected: 200 statusCodeExpected: 200
}) })
}) })
@ -282,26 +278,23 @@ describe('Test video channels API validator', function () {
describe('When deleting a video channel', function () { describe('When deleting a video channel', function () {
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
await deleteVideoChannel(server.url, 'coucou', videoChannelUUID, 401) await deleteVideoChannel(server.url, 'coucou', 'super_channel', 401)
}) })
it('Should fail with another authenticated user', async function () { it('Should fail with another authenticated user', async function () {
await deleteVideoChannel(server.url, accessTokenUser, videoChannelUUID, 403) await deleteVideoChannel(server.url, accessTokenUser, 'super_channel', 403)
}) })
it('Should fail with an unknown video channel id', async function () { it('Should fail with an unknown video channel id', async function () {
await deleteVideoChannel(server.url, server.accessToken,454554, 404) await deleteVideoChannel(server.url, server.accessToken,'super_channel2', 404)
}) })
it('Should succeed with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await deleteVideoChannel(server.url, server.accessToken, videoChannelUUID) await deleteVideoChannel(server.url, server.accessToken, 'super_channel')
}) })
it('Should fail to delete the last user video channel', async function () { it('Should fail to delete the last user video channel', async function () {
const res = await getVideoChannelsList(server.url, 0, 1) await deleteVideoChannel(server.url, server.accessToken, 'root_channel', 409)
const lastVideoChannelUUID = res.body.data[0].uuid
await deleteVideoChannel(server.url, server.accessToken, lastVideoChannelUUID, 409)
}) })
}) })

View File

@ -311,7 +311,7 @@ describe('Test follows', function () {
likes: 1, likes: 1,
dislikes: 1, dislikes: 1,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal isLocal
}, },

View File

@ -71,7 +71,7 @@ describe('Test handle downs', function () {
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
commentsEnabled: true, commentsEnabled: true,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal: false isLocal: false
}, },

View File

@ -3,7 +3,7 @@
import * as chai from 'chai' import * as chai from 'chai'
import 'mocha' import 'mocha'
import { createUser, doubleFollow, flushAndRunMultipleServers, follow, getVideosList, unfollow, userLogin } from '../../utils' import { createUser, doubleFollow, flushAndRunMultipleServers, follow, getVideosList, unfollow, userLogin } from '../../utils'
import { getMyUserInformation, killallServers, ServerInfo, uploadVideo } from '../../utils/index' import { killallServers, ServerInfo, uploadVideo } from '../../utils/index'
import { setAccessTokensToServers } from '../../utils/users/login' import { setAccessTokensToServers } from '../../utils/users/login'
import { Video, VideoChannel } from '../../../../shared/models/videos' import { Video, VideoChannel } from '../../../../shared/models/videos'
import { waitJobs } from '../../utils/server/jobs' import { waitJobs } from '../../utils/server/jobs'
@ -18,8 +18,7 @@ const expect = chai.expect
describe('Test users subscriptions', function () { describe('Test users subscriptions', function () {
let servers: ServerInfo[] = [] let servers: ServerInfo[] = []
const users: { accessToken: string, videoChannelName: string }[] = [] const users: { accessToken: string }[] = []
let rootChannelNameServer1: string
before(async function () { before(async function () {
this.timeout(120000) this.timeout(120000)
@ -32,19 +31,13 @@ describe('Test users subscriptions', function () {
// Server 1 and server 2 follow each other // Server 1 and server 2 follow each other
await doubleFollow(servers[0], servers[1]) await doubleFollow(servers[0], servers[1])
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
rootChannelNameServer1 = res.body.videoChannels[0].name
{ {
for (const server of servers) { for (const server of servers) {
const user = { username: 'user' + server.serverNumber, password: 'password' } const user = { username: 'user' + server.serverNumber, password: 'password' }
await createUser(server.url, server.accessToken, user.username, user.password) await createUser(server.url, server.accessToken, user.username, user.password)
const accessToken = await userLogin(server, user) const accessToken = await userLogin(server, user)
const res = await getMyUserInformation(server.url, accessToken) users.push({ accessToken })
const videoChannels: VideoChannel[] = res.body.videoChannels
users.push({ accessToken, videoChannelName: videoChannels[0].name })
const videoName1 = 'video 1-' + server.serverNumber const videoName1 = 'video 1-' + server.serverNumber
await uploadVideo(server.url, accessToken, { name: videoName1 }) await uploadVideo(server.url, accessToken, { name: videoName1 })
@ -64,10 +57,10 @@ describe('Test users subscriptions', function () {
}) })
it('User of server 1 should follow user of server 3 and root of server 1', async function () { it('User of server 1 should follow user of server 3 and root of server 1', async function () {
this.timeout(30000) this.timeout(60000)
await addUserSubscription(servers[0].url, users[0].accessToken, users[2].videoChannelName + '@localhost:9003') await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
await addUserSubscription(servers[0].url, users[0].accessToken, rootChannelNameServer1 + '@localhost:9001') await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001')
await waitJobs(servers) await waitJobs(servers)
@ -103,8 +96,8 @@ describe('Test users subscriptions', function () {
expect(subscriptions).to.be.an('array') expect(subscriptions).to.be.an('array')
expect(subscriptions).to.have.lengthOf(2) expect(subscriptions).to.have.lengthOf(2)
expect(subscriptions[0].name).to.equal(users[2].videoChannelName) expect(subscriptions[0].name).to.equal('user3_channel')
expect(subscriptions[1].name).to.equal(rootChannelNameServer1) expect(subscriptions[1].name).to.equal('root_channel')
} }
}) })
@ -131,7 +124,7 @@ describe('Test users subscriptions', function () {
}) })
it('Should upload a video by root on server 1 and see it in the subscription videos', async function () { it('Should upload a video by root on server 1 and see it in the subscription videos', async function () {
this.timeout(30000) this.timeout(60000)
const videoName = 'video server 1 added after follow' const videoName = 'video server 1 added after follow'
await uploadVideo(servers[0].url, servers[0].accessToken, { name: videoName }) await uploadVideo(servers[0].url, servers[0].accessToken, { name: videoName })
@ -172,7 +165,7 @@ describe('Test users subscriptions', function () {
}) })
it('Should have server 1 follow server 3 and display server 3 videos', async function () { it('Should have server 1 follow server 3 and display server 3 videos', async function () {
this.timeout(30000) this.timeout(60000)
await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken)
@ -190,7 +183,7 @@ describe('Test users subscriptions', function () {
}) })
it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () { it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () {
this.timeout(30000) this.timeout(60000)
await unfollow(servers[0].url, servers[0].accessToken, servers[2]) await unfollow(servers[0].url, servers[0].accessToken, servers[2])
@ -230,7 +223,7 @@ describe('Test users subscriptions', function () {
}) })
it('Should remove user of server 3 subscription', async function () { it('Should remove user of server 3 subscription', async function () {
await removeUserSubscription(servers[0].url, users[0].accessToken, users[2].videoChannelName + '@localhost:9003') await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
await waitJobs(servers) await waitJobs(servers)
}) })
@ -249,7 +242,7 @@ describe('Test users subscriptions', function () {
}) })
it('Should remove the root subscription and not display the videos anymore', async function () { it('Should remove the root subscription and not display the videos anymore', async function () {
await removeUserSubscription(servers[0].url, users[0].accessToken, rootChannelNameServer1 + '@localhost:9001') await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001')
await waitJobs(servers) await waitJobs(servers)
@ -275,9 +268,9 @@ describe('Test users subscriptions', function () {
}) })
it('Should follow user of server 3 again', async function () { it('Should follow user of server 3 again', async function () {
this.timeout(30000) this.timeout(60000)
await addUserSubscription(servers[0].url, users[0].accessToken, users[2].videoChannelName + '@localhost:9003') await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003')
await waitJobs(servers) await waitJobs(servers)

View File

@ -12,10 +12,9 @@ import {
getVideoChannelsList, getVideoChannelsList,
removeUser, removeUser,
updateMyUser, updateMyUser,
userLogin, userLogin
wait
} from '../../utils' } from '../../utils'
import { flushTests, getMyUserInformation, killallServers, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../utils/index' import { getMyUserInformation, killallServers, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../utils/index'
import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../utils/users/accounts' import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../utils/users/accounts'
import { setAccessTokensToServers } from '../../utils/users/login' import { setAccessTokensToServers } from '../../utils/users/login'
import { User } from '../../../../shared/models/users' import { User } from '../../../../shared/models/users'
@ -172,7 +171,7 @@ describe('Test users with multiple servers', function () {
const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
const videoChannelDeleted = resVideoChannels.body.data.find(a => { const videoChannelDeleted = resVideoChannels.body.data.find(a => {
return a.displayName === 'Default user1 channel' && a.host === 'localhost:9001' return a.displayName === 'Main user1 channel' && a.host === 'localhost:9001'
}) as VideoChannel }) as VideoChannel
expect(videoChannelDeleted).not.to.be.undefined expect(videoChannelDeleted).not.to.be.undefined
} }
@ -189,7 +188,7 @@ describe('Test users with multiple servers', function () {
const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
const videoChannelDeleted = resVideoChannels.body.data.find(a => { const videoChannelDeleted = resVideoChannels.body.data.find(a => {
return a.name === 'Default user1 channel' && a.host === 'localhost:9001' return a.name === 'Main user1 channel' && a.host === 'localhost:9001'
}) as VideoChannel }) as VideoChannel
expect(videoChannelDeleted).to.be.undefined expect(videoChannelDeleted).to.be.undefined
} }

View File

@ -6,7 +6,6 @@ import { join } from 'path'
import * as request from 'supertest' import * as request from 'supertest'
import { VideoPrivacy } from '../../../../shared/models/videos' import { VideoPrivacy } from '../../../../shared/models/videos'
import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
import { import {
addVideoChannel, addVideoChannel,
checkVideoFilesWereRemoved, checkVideoFilesWereRemoved,
@ -60,6 +59,7 @@ describe('Test multiple servers', function () {
{ {
const videoChannel = { const videoChannel = {
name: 'super_channel_name',
displayName: 'my channel', displayName: 'my channel',
description: 'super channel' description: 'super channel'
} }
@ -201,7 +201,7 @@ describe('Test multiple servers', function () {
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ], tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
channel: { channel: {
name: 'Default user1 channel', name: 'Main user1 channel',
description: 'super channel', description: 'super channel',
isLocal isLocal
}, },
@ -307,7 +307,7 @@ describe('Test multiple servers', function () {
tags: [ 'tag1p3' ], tags: [ 'tag1p3' ],
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal isLocal
}, },
@ -339,7 +339,7 @@ describe('Test multiple servers', function () {
tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ], tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal isLocal
}, },
@ -647,7 +647,7 @@ describe('Test multiple servers', function () {
tags: [ 'tag_up_1', 'tag_up_2' ], tags: [ 'tag_up_1', 'tag_up_2' ],
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal isLocal
}, },
@ -967,7 +967,7 @@ describe('Test multiple servers', function () {
tags: [ ], tags: [ ],
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal isLocal
}, },

View File

@ -56,7 +56,7 @@ describe('Test a single server', function () {
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
commentsEnabled: true, commentsEnabled: true,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal: true isLocal: true
}, },
@ -87,7 +87,7 @@ describe('Test a single server', function () {
duration: 5, duration: 5,
commentsEnabled: false, commentsEnabled: false,
channel: { channel: {
name: 'Default root channel', name: 'Main root channel',
description: '', description: '',
isLocal: true isLocal: true
}, },

View File

@ -4,12 +4,13 @@ import * as chai from 'chai'
import 'mocha' import 'mocha'
import { User, Video } from '../../../../shared/index' import { User, Video } from '../../../../shared/index'
import { import {
createUser,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getVideoChannelVideos, testImage, getVideoChannelVideos, serverLogin, testImage,
updateVideo, updateVideo,
updateVideoChannelAvatar, updateVideoChannelAvatar,
uploadVideo, wait uploadVideo, wait, userLogin
} from '../../utils' } from '../../utils'
import { import {
addVideoChannel, addVideoChannel,
@ -33,9 +34,7 @@ describe('Test video channels', function () {
let userInfo: User let userInfo: User
let accountUUID: string let accountUUID: string
let firstVideoChannelId: number let firstVideoChannelId: number
let firstVideoChannelUUID: string
let secondVideoChannelId: number let secondVideoChannelId: number
let secondVideoChannelUUID: string
let videoUUID: string let videoUUID: string
before(async function () { before(async function () {
@ -54,7 +53,6 @@ describe('Test video channels', function () {
accountUUID = user.account.uuid accountUUID = user.account.uuid
firstVideoChannelId = user.videoChannels[0].id firstVideoChannelId = user.videoChannels[0].id
firstVideoChannelUUID = user.videoChannels[0].uuid
} }
await waitJobs(servers) await waitJobs(servers)
@ -73,13 +71,13 @@ describe('Test video channels', function () {
{ {
const videoChannel = { const videoChannel = {
name: 'second_video_channel',
displayName: 'second video channel', displayName: 'second video channel',
description: 'super video channel description', description: 'super video channel description',
support: 'super video channel support text' support: 'super video channel support text'
} }
const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel)
secondVideoChannelId = res.body.videoChannel.id secondVideoChannelId = res.body.videoChannel.id
secondVideoChannelUUID = res.body.videoChannel.uuid
} }
// The channel is 1 is propagated to servers 2 // The channel is 1 is propagated to servers 2
@ -99,7 +97,10 @@ describe('Test video channels', function () {
expect(userInfo.videoChannels).to.have.lengthOf(2) expect(userInfo.videoChannels).to.have.lengthOf(2)
const videoChannels = userInfo.videoChannels const videoChannels = userInfo.videoChannels
expect(videoChannels[0].displayName).to.equal('Default root channel') expect(videoChannels[0].name).to.equal('root_channel')
expect(videoChannels[0].displayName).to.equal('Main root channel')
expect(videoChannels[1].name).to.equal('second_video_channel')
expect(videoChannels[1].displayName).to.equal('second video channel') expect(videoChannels[1].displayName).to.equal('second video channel')
expect(videoChannels[1].description).to.equal('super video channel description') expect(videoChannels[1].description).to.equal('super video channel description')
expect(videoChannels[1].support).to.equal('super video channel support text') expect(videoChannels[1].support).to.equal('super video channel support text')
@ -112,7 +113,10 @@ describe('Test video channels', function () {
expect(res.body.data).to.have.lengthOf(2) expect(res.body.data).to.have.lengthOf(2)
const videoChannels = res.body.data const videoChannels = res.body.data
expect(videoChannels[0].displayName).to.equal('Default root channel') expect(videoChannels[0].name).to.equal('root_channel')
expect(videoChannels[0].displayName).to.equal('Main root channel')
expect(videoChannels[1].name).to.equal('second_video_channel')
expect(videoChannels[1].displayName).to.equal('second video channel') expect(videoChannels[1].displayName).to.equal('second video channel')
expect(videoChannels[1].description).to.equal('super video channel description') expect(videoChannels[1].description).to.equal('super video channel description')
expect(videoChannels[1].support).to.equal('super video channel support text') expect(videoChannels[1].support).to.equal('super video channel support text')
@ -125,6 +129,7 @@ describe('Test video channels', function () {
expect(res.body.data).to.have.lengthOf(1) expect(res.body.data).to.have.lengthOf(1)
const videoChannels = res.body.data const videoChannels = res.body.data
expect(videoChannels[0].name).to.equal('second_video_channel')
expect(videoChannels[0].displayName).to.equal('second video channel') expect(videoChannels[0].displayName).to.equal('second video channel')
expect(videoChannels[0].description).to.equal('super video channel description') expect(videoChannels[0].description).to.equal('super video channel description')
expect(videoChannels[0].support).to.equal('super video channel support text') expect(videoChannels[0].support).to.equal('super video channel support text')
@ -136,7 +141,8 @@ describe('Test video channels', function () {
expect(res.body.total).to.equal(2) expect(res.body.total).to.equal(2)
expect(res.body.data).to.be.an('array') expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1) expect(res.body.data).to.have.lengthOf(1)
expect(res.body.data[0].displayName).to.equal('Default root channel') expect(res.body.data[0].name).to.equal('root_channel')
expect(res.body.data[0].displayName).to.equal('Main root channel')
}) })
it('Should update video channel', async function () { it('Should update video channel', async function () {
@ -148,7 +154,7 @@ describe('Test video channels', function () {
support: 'video channel support text updated' support: 'video channel support text updated'
} }
await updateVideoChannel(servers[0].url, servers[0].accessToken, secondVideoChannelId, videoChannelAttributes) await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes)
await waitJobs(servers) await waitJobs(servers)
}) })
@ -160,6 +166,7 @@ describe('Test video channels', function () {
expect(res.body.total).to.equal(2) expect(res.body.total).to.equal(2)
expect(res.body.data).to.be.an('array') expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1) expect(res.body.data).to.have.lengthOf(1)
expect(res.body.data[0].name).to.equal('second_video_channel')
expect(res.body.data[0].displayName).to.equal('video channel updated') expect(res.body.data[0].displayName).to.equal('video channel updated')
expect(res.body.data[0].description).to.equal('video channel description updated') expect(res.body.data[0].description).to.equal('video channel description updated')
expect(res.body.data[0].support).to.equal('video channel support text updated') expect(res.body.data[0].support).to.equal('video channel support text updated')
@ -174,7 +181,7 @@ describe('Test video channels', function () {
await updateVideoChannelAvatar({ await updateVideoChannelAvatar({
url: servers[0].url, url: servers[0].url,
accessToken: servers[0].accessToken, accessToken: servers[0].accessToken,
videoChannelId: secondVideoChannelId, videoChannelName: 'second_video_channel',
fixture fixture
}) })
@ -192,9 +199,10 @@ describe('Test video channels', function () {
}) })
it('Should get video channel', async function () { it('Should get video channel', async function () {
const res = await getVideoChannel(servers[0].url, secondVideoChannelId) const res = await getVideoChannel(servers[0].url, 'second_video_channel')
const videoChannel = res.body const videoChannel = res.body
expect(videoChannel.name).to.equal('second_video_channel')
expect(videoChannel.displayName).to.equal('video channel updated') expect(videoChannel.displayName).to.equal('video channel updated')
expect(videoChannel.description).to.equal('video channel description updated') expect(videoChannel.description).to.equal('video channel description updated')
expect(videoChannel.support).to.equal('video channel support text updated') expect(videoChannel.support).to.equal('video channel support text updated')
@ -204,7 +212,8 @@ describe('Test video channels', function () {
this.timeout(10000) this.timeout(10000)
for (const server of servers) { for (const server of servers) {
const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondVideoChannelUUID, 0, 5) const channelURI = 'second_video_channel@localhost:9001'
const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
expect(res1.body.total).to.equal(1) expect(res1.body.total).to.equal(1)
expect(res1.body.data).to.be.an('array') expect(res1.body.data).to.be.an('array')
expect(res1.body.data).to.have.lengthOf(1) expect(res1.body.data).to.have.lengthOf(1)
@ -224,10 +233,12 @@ describe('Test video channels', function () {
this.timeout(10000) this.timeout(10000)
for (const server of servers) { for (const server of servers) {
const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondVideoChannelUUID, 0, 5) const secondChannelURI = 'second_video_channel@localhost:9001'
const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5)
expect(res1.body.total).to.equal(0) expect(res1.body.total).to.equal(0)
const res2 = await getVideoChannelVideos(server.url, server.accessToken, firstVideoChannelUUID, 0, 5) const channelURI = 'root_channel@localhost:9001'
const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
expect(res2.body.total).to.equal(1) expect(res2.body.total).to.equal(1)
const videos: Video[] = res2.body.data const videos: Video[] = res2.body.data
@ -238,7 +249,7 @@ describe('Test video channels', function () {
}) })
it('Should delete video channel', async function () { it('Should delete video channel', async function () {
await deleteVideoChannel(servers[0].url, servers[0].accessToken, secondVideoChannelId) await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel')
}) })
it('Should have video channel deleted', async function () { it('Should have video channel deleted', async function () {
@ -247,7 +258,23 @@ describe('Test video channels', function () {
expect(res.body.total).to.equal(1) expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array') expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1) expect(res.body.data).to.have.lengthOf(1)
expect(res.body.data[0].displayName).to.equal('Default root channel') expect(res.body.data[0].displayName).to.equal('Main root channel')
})
it('Should create the main channel with an uuid if there is a conflict', async function () {
{
const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel)
}
{
await createUser(servers[ 0 ].url, servers[ 0 ].accessToken, 'toto', 'password')
const accessToken = await userLogin(servers[ 0 ], { username: 'toto', password: 'password' })
const res = await getMyUserInformation(servers[ 0 ].url, accessToken)
const videoChannel = res.body.videoChannels[ 0 ]
expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
}
}) })
after(async function () { after(async function () {

View File

@ -54,6 +54,7 @@ describe('Test update host scripts', function () {
// Create channel // Create channel
const videoChannel = { const videoChannel = {
name: 'second_channel',
displayName: 'second video channel', displayName: 'second video channel',
description: 'super video channel description' description: 'super video channel description'
} }

View File

@ -66,6 +66,7 @@ function getRandomInt (min, max) {
function createCustomChannel (server: ServerInfo) { function createCustomChannel (server: ServerInfo) {
const videoChannel = { const videoChannel = {
name: Date.now().toString(),
displayName: Date.now().toString(), displayName: Date.now().toString(),
description: Date.now().toString() description: Date.now().toString()
} }

View File

@ -97,10 +97,10 @@ function updateVideoChannelAvatar (options: {
url: string, url: string,
accessToken: string, accessToken: string,
fixture: string, fixture: string,
videoChannelId: string | number videoChannelName: string | number
}) { }) {
const path = '/api/v1/video-channels/' + options.videoChannelId + '/avatar/pick' const path = '/api/v1/video-channels/' + options.videoChannelName + '/avatar/pick'
return updateAvatarRequest(Object.assign(options, { path })) return updateAvatarRequest(Object.assign(options, { path }))
} }

View File

@ -199,13 +199,13 @@ function getAccountVideos (
function getVideoChannelVideos ( function getVideoChannelVideos (
url: string, url: string,
accessToken: string, accessToken: string,
videoChannelId: number | string, videoChannelName: string,
start: number, start: number,
count: number, count: number,
sort?: string, sort?: string,
query: { nsfw?: boolean } = {} query: { nsfw?: boolean } = {}
) { ) {
const path = '/api/v1/video-channels/' + videoChannelId + '/videos' const path = '/api/v1/video-channels/' + videoChannelName + '/videos'
return makeGetRequest({ return makeGetRequest({
url, url,

View File

@ -1,4 +1,5 @@
export interface VideoChannelCreate { export interface VideoChannelCreate {
name: string
displayName: string displayName: string
description?: string description?: string
support?: string support?: string