Support short uuid for GET video/playlist

This commit is contained in:
Chocobozzz 2021-06-28 17:30:59 +02:00 committed by Chocobozzz
parent 62ddc31a9e
commit d4a8e7a65f
94 changed files with 1029 additions and 673 deletions

View File

@ -122,7 +122,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
}
getVideoUrl (videoBlock: VideoBlacklist) {
return Video.buildClientUrl(videoBlock.video.uuid)
return Video.buildWatchUrl(videoBlock.video)
}
toHtml (text: string) {

View File

@ -1,7 +1,7 @@
import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core'
import { Notifier, RestPagination, RestTable } from '@app/core'
import { VideoImportService } from '@app/shared/shared-main'
import { Video, VideoImportService } from '@app/shared/shared-main'
import { VideoImport, VideoImportState } from '@shared/models'
@Component({
@ -55,11 +55,11 @@ export class MyVideoImportsComponent extends RestTable implements OnInit {
}
getVideoUrl (video: { uuid: string }) {
return '/w/' + video.uuid
return Video.buildWatchUrl(video)
}
getEditVideoUrl (video: { uuid: string }) {
return '/videos/update/' + video.uuid
return Video.buildUpdateUrl(video)
}
protected reloadData () {

View File

@ -1,7 +1,7 @@
import { forkJoin } from 'rxjs'
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { VideoChannel } from '@app/shared/shared-main'
import { Video, VideoChannel } from '@app/shared/shared-main'
import { SearchService } from '@app/shared/shared-search'
@Component({
@ -39,7 +39,7 @@ export class RemoteInteractionComponent implements OnInit {
if (videoResult.data.length !== 0) {
const video = videoResult.data[0]
redirectUrl = '/w/' + video.uuid
redirectUrl = Video.buildWatchUrl(video)
} else if (channelResult.data.length !== 0) {
const channel = new VideoChannel(channelResult.data[0])

View File

@ -1,7 +1,7 @@
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'
import { ResultList } from '@shared/models/result-list.model'
import { ResultList } from '@shared/models'
export abstract class AbstractLazyLoadResolver <T> implements Resolve<any> {
protected router: Router

View File

@ -19,6 +19,6 @@ export class PlaylistLazyLoadResolver extends AbstractLazyLoadResolver<VideoPlay
}
protected buildUrl (playlist: VideoPlaylist) {
return '/w/p/' + playlist.uuid
return VideoPlaylist.buildWatchUrl(playlist)
}
}

View File

@ -19,6 +19,6 @@ export class VideoLazyLoadResolver extends AbstractLazyLoadResolver<Video> {
}
protected buildUrl (video: Video) {
return '/w/' + video.uuid
return Video.buildWatchUrl(video)
}
}

View File

@ -1,11 +1,11 @@
import { forkJoin } from 'rxjs'
import { AfterViewChecked, AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
import { Router } from '@angular/router'
import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
import { scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms'
import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LiveVideoService } from '@app/shared/shared-video-live'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy } from '@shared/models'
@ -127,7 +127,7 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
() => {
this.notifier.success($localize`Live published.`)
this.router.navigate(['/w', video.uuid])
this.router.navigateByUrl(Video.buildWatchUrl(video))
},
err => {

View File

@ -1,16 +1,16 @@
import { UploadState, UploadxOptions, UploadxService } from 'ngx-uploadx'
import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
import { Router } from '@angular/router'
import { UploadxOptions, UploadState, UploadxService } from 'ngx-uploadx'
import { UploaderXFormData } from './uploaderx-form-data'
import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService, UserService } from '@app/core'
import { scrollToTop, genericUploadErrorHandler } from '@app/helpers'
import { genericUploadErrorHandler, scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms'
import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { BytesPipe, Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { VideoPrivacy } from '@shared/models'
import { UploaderXFormData } from './uploaderx-form-data'
import { VideoSend } from './video-send'
import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
@Component({
selector: 'my-video-upload',
@ -243,7 +243,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
this.isUploadingVideo = false
this.notifier.success($localize`Video published.`)
this.router.navigate([ '/w', video.uuid ])
this.router.navigateByUrl(Video.buildWatchUrl(video))
},
err => {

View File

@ -1,7 +1,7 @@
<div class="margin-content">
<div class="title-page title-page-single">
<span class="mr-1" i18n>Update</span>
<a [routerLink]="[ '/w', video.uuid ]">{{ video?.name }}</a>
<a [routerLink]="getVideoUrl()">{{ video?.name }}</a>
</div>
<form novalidate [formGroup]="form">

View File

@ -5,7 +5,7 @@ import { Component, HostListener, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { Notifier } from '@app/core'
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
import { Video, VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LiveVideoService } from '@app/shared/shared-video-live'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { LiveVideo, LiveVideoUpdate, VideoPrivacy } from '@shared/models'
@ -156,7 +156,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
this.isUpdatingVideo = false
this.loadingBar.useRef().complete()
this.notifier.success($localize`Video updated.`)
this.router.navigate([ '/w', this.video.uuid ])
this.router.navigateByUrl(Video.buildWatchUrl(this.video))
},
err => {
@ -175,4 +175,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
pluginData: this.video.pluginData
})
}
getVideoUrl () {
return Video.buildWatchUrl(this.videoDetails)
}
}

View File

@ -20,7 +20,7 @@
</a>
</div>
<a [routerLink]="['/w', video.uuid, { 'threadId': comment.threadId }]" class="comment-date" [title]="comment.createdAt">
<a [routerLink]="['/w', video.shortUUID, { 'threadId': comment.threadId }]" class="comment-date" [title]="comment.createdAt">
{{ comment.createdAt | myFromNow }}
</a>
</div>
@ -45,7 +45,7 @@
<ng-container *ngIf="comment.isDeleted">
<div class="comment-account-date">
<span class="comment-account" i18n>Deleted</span>
<a [routerLink]="['/w', video.uuid, { 'threadId': comment.threadId }]"
<a [routerLink]="['/w', video.shortUUID, { 'threadId': comment.threadId }]"
class="comment-date">{{ comment.createdAt | myFromNow }}</a>
</div>

View File

@ -247,7 +247,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
this.componentPagination.totalItems = null
this.totalNotDeletedComments = null
this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video.uuid)
this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video)
this.loadMoreThreads()
}
}

View File

@ -312,7 +312,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
getVideoUrl () {
if (!this.video.url) {
return this.video.originInstanceUrl + VideoDetails.buildClientUrl(this.video.uuid)
return this.video.originInstanceUrl + VideoDetails.buildWatchUrl(this.video)
}
return this.video.url
}
@ -415,7 +415,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private loadVideo (videoId: string) {
// Video did not change
if (this.video && this.video.uuid === videoId) return
if (
this.video &&
(this.video.uuid === videoId || this.video.shortUUID === videoId)
) return
if (this.player) this.player.pause()
@ -489,7 +492,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private loadPlaylist (playlistId: string) {
// Playlist did not change
if (this.playlist && this.playlist.uuid === playlistId) return
if (
this.playlist &&
(this.playlist.uuid === playlistId || this.playlist.shortUUID === playlistId)
) return
this.playlistService.getVideoPlaylist(playlistId)
.pipe(
@ -772,13 +778,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private flushPlayer () {
// Remove player if it exists
if (this.player) {
try {
this.player.dispose()
this.player = undefined
} catch (err) {
console.error('Cannot dispose player.', err)
}
if (!this.player) return
try {
this.player.dispose()
this.player = undefined
} catch (err) {
console.error('Cannot dispose player.', err)
}
}

View File

@ -116,11 +116,11 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
}
getVideoUrl (abuse: AdminAbuse) {
return Video.buildClientUrl(abuse.video.uuid)
return Video.buildWatchUrl(abuse.video)
}
getCommentUrl (abuse: AdminAbuse) {
return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId
return Video.buildWatchUrl(abuse.comment.video) + ';threadId=' + abuse.comment.threadId
}
getAccountUrl (abuse: ProcessedAbuse) {

View File

@ -6,7 +6,7 @@ import { Component, Input, ViewEncapsulation } from '@angular/core'
templateUrl: './link.component.html'
})
export class LinkComponent {
@Input() internalLink?: any[]
@Input() internalLink?: string | any[]
@Input() href?: string
@Input() target?: string

View File

@ -12,6 +12,7 @@ import {
UserRight,
VideoInfo
} from '@shared/models'
import { Video } from '../video'
export class UserNotification implements UserNotificationServer {
id: number
@ -238,7 +239,7 @@ export class UserNotification implements UserNotificationServer {
}
private buildVideoUrl (video: { uuid: string }) {
return '/w/' + video.uuid
return Video.buildWatchUrl(video)
}
private buildAccountUrl (account: { name: string, host: string }) {

View File

@ -26,12 +26,18 @@ export class Video implements VideoServerModel {
licence: VideoConstant<number>
language: VideoConstant<string>
privacy: VideoConstant<VideoPrivacy>
description: string
duration: number
durationLabel: string
id: number
uuid: string
shortUUID: string
isLocal: boolean
name: string
serverHost: string
thumbnailPath: string
@ -85,8 +91,12 @@ export class Video implements VideoServerModel {
pluginData?: any
static buildClientUrl (videoUUID: string) {
return '/w/' + videoUUID
static buildWatchUrl (video: Partial<Pick<Video, 'uuid' | 'shortUUID'>>) {
return '/w/' + (video.shortUUID || video.uuid)
}
static buildUpdateUrl (video: Pick<Video, 'uuid'>) {
return '/videos/update/' + video.uuid
}
constructor (hash: VideoServerModel, translations = {}) {
@ -109,6 +119,7 @@ export class Video implements VideoServerModel {
this.id = hash.id
this.uuid = hash.uuid
this.shortUUID = hash.shortUUID
this.isLocal = hash.isLocal
this.name = hash.name

View File

@ -1,5 +1,5 @@
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
import { VideoDetails } from '@app/shared/shared-main'
import { Video, VideoDetails } from '@app/shared/shared-main'
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { VideoCaption } from '@shared/models'
@ -98,14 +98,15 @@ export class VideoShareComponent {
getVideoUrl () {
let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin
baseUrl += '/w/' + this.video.uuid
baseUrl += Video.buildWatchUrl(this.video)
const options = this.getVideoOptions(baseUrl)
return buildVideoLink(options)
}
getPlaylistUrl () {
const base = window.location.origin + '/w/p/' + this.playlist.uuid
const base = window.location.origin + VideoPlaylist.buildWatchUrl(this.playlist)
if (!this.includeVideoInPlaylist) return base

View File

@ -12,7 +12,7 @@ export class VideoThumbnailComponent {
@Input() video: Video
@Input() nsfw = false
@Input() videoRouterLink: any[]
@Input() videoRouterLink: string | any[]
@Input() queryParams: { [ p: string ]: any }
@Input() videoHref: string
@Input() videoTarget: string
@ -57,7 +57,7 @@ export class VideoThumbnailComponent {
getVideoRouterLink () {
if (this.videoRouterLink) return this.videoRouterLink
return [ '/w', this.video.uuid ]
return Video.buildWatchUrl(this.video)
}
onWatchLaterClick (event: Event) {

View File

@ -1,5 +1,5 @@
import { getAbsoluteAPIUrl } from '@app/helpers'
import { Account, Actor } from '@app/shared/shared-main'
import { Account, Actor, Video } from '@app/shared/shared-main'
import { Account as AccountInterface, VideoComment as VideoCommentServerModel, VideoCommentAdmin as VideoCommentAdminServerModel } from '@shared/models'
export class VideoComment implements VideoCommentServerModel {
@ -85,7 +85,7 @@ export class VideoCommentAdmin implements VideoCommentAdminServerModel {
id: hash.video.id,
uuid: hash.video.uuid,
name: hash.video.name,
localUrl: '/w/' + hash.video.uuid
localUrl: Video.buildWatchUrl(hash.video)
}
this.localUrl = this.video.localUrl + ';threadId=' + this.threadId

View File

@ -9,6 +9,7 @@ import {
FeedFormat,
ResultList,
ThreadsResultList,
Video,
VideoComment as VideoCommentServerModel,
VideoCommentAdmin,
VideoCommentCreate,
@ -127,7 +128,7 @@ export class VideoCommentService {
)
}
getVideoCommentsFeeds (videoUUID?: string) {
getVideoCommentsFeeds (video: Pick<Video, 'uuid'>) {
const feeds = [
{
format: FeedFormat.RSS,
@ -146,9 +147,9 @@ export class VideoCommentService {
}
]
if (videoUUID !== undefined) {
if (video !== undefined) {
for (const feed of feeds) {
feed.url += '?videoId=' + videoUUID
feed.url += '?videoId=' + video.uuid
}
}

View File

@ -85,7 +85,7 @@ export class VideoMiniatureComponent implements OnInit {
playlistElementId?: number
}
videoRouterLink: any[] = []
videoRouterLink: string | any[] = []
videoHref: string
videoTarget: string
@ -120,7 +120,7 @@ export class VideoMiniatureComponent implements OnInit {
buildVideoLink () {
if (this.videoLinkType === 'internal' || !this.video.url) {
this.videoRouterLink = [ '/w', this.video.uuid ]
this.videoRouterLink = Video.buildWatchUrl(this.video)
return
}

View File

@ -66,7 +66,7 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
buildRouterLink () {
if (!this.playlist) return null
return [ '/w/p', this.playlist.uuid ]
return VideoPlaylist.buildWatchUrl(this.playlist)
}
buildRouterQuery () {

View File

@ -39,7 +39,7 @@ export class VideoPlaylistMiniatureComponent implements OnInit {
}
if (this.linkType === 'internal' || !this.playlist.url) {
this.routerLink = [ '/w/p', this.playlist.uuid ]
this.routerLink = VideoPlaylist.buildWatchUrl(this.playlist)
return
}

View File

@ -13,6 +13,8 @@ import {
export class VideoPlaylist implements ServerVideoPlaylist {
id: number
uuid: string
shortUUID: string
isLocal: boolean
url: string
@ -41,11 +43,17 @@ export class VideoPlaylist implements ServerVideoPlaylist {
videoChannelBy?: string
static buildWatchUrl (playlist: Pick<VideoPlaylist, 'uuid' | 'shortUUID'>) {
return '/w/p/' + (playlist.uuid || playlist.shortUUID)
}
constructor (hash: ServerVideoPlaylist, translations: {}) {
const absoluteAPIUrl = getAbsoluteAPIUrl()
this.id = hash.id
this.uuid = hash.uuid
this.shortUUID = hash.shortUUID
this.url = hash.url
this.isLocal = hash.isLocal

View File

@ -131,6 +131,7 @@
"sanitize-html": "2.x",
"sequelize": "6.6.2",
"sequelize-typescript": "^2.0.0-beta.1",
"short-uuid": "^4.2.0",
"sitemap": "^7.0.0",
"socket.io": "^4.0.1",
"sql-formatter": "^4.0.0-beta.0",
@ -138,7 +139,6 @@
"tsconfig-paths": "^3.9.0",
"tslib": "^2.0.0",
"useragent": "^2.3.0",
"uuid": "^8.1.0",
"validator": "^13.0.0",
"webfinger.js": "^2.6.6",
"webtorrent": "^1.0.0",

View File

@ -1,7 +1,7 @@
import * as express from 'express'
import * as RateLimit from 'express-rate-limit'
import { v4 as uuidv4 } from 'uuid'
import { logger } from '@server/helpers/logger'
import { buildUUID } from '@server/helpers/uuid'
import { CONFIG } from '@server/initializers/config'
import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth'
import { handleOAuthToken } from '@server/lib/auth/oauth'
@ -107,7 +107,7 @@ function getScopedTokens (req: express.Request, res: express.Response) {
async function renewScopedTokens (req: express.Request, res: express.Response) {
const user = res.locals.oauth.token.user
user.feedToken = uuidv4()
user.feedToken = buildUUID()
await user.save()
return res.json({

View File

@ -1,6 +1,8 @@
import * as express from 'express'
import { join } from 'path'
import { uuidToShort } from '@server/helpers/uuid'
import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists'
import { Hooks } from '@server/lib/plugins/hooks'
import { getServerActor } from '@server/models/application/application'
import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
@ -43,7 +45,6 @@ import {
import { AccountModel } from '../../models/account/account'
import { VideoPlaylistModel } from '../../models/video/video-playlist'
import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
import { Hooks } from '@server/lib/plugins/hooks'
const reqThumbnailFile = createReqFiles([ 'thumbnailfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { thumbnailfile: CONFIG.STORAGE.TMP_DIR })
@ -199,6 +200,7 @@ async function addVideoPlaylist (req: express.Request, res: express.Response) {
return res.json({
videoPlaylist: {
id: videoPlaylistCreated.id,
shortUUID: uuidToShort(videoPlaylistCreated.uuid),
uuid: videoPlaylistCreated.uuid
}
})

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { v4 as uuidv4 } from 'uuid'
import { createReqFiles } from '@server/helpers/express-utils'
import { buildUUID, uuidToShort } from '@server/helpers/uuid'
import { CONFIG } from '@server/initializers/config'
import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants'
import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
@ -11,12 +11,12 @@ import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator
import { VideoLiveModel } from '@server/models/video/video-live'
import { MVideoDetails, MVideoFullLight } from '@server/types/models'
import { LiveVideoCreate, LiveVideoUpdate, VideoState } from '../../../../shared'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers/database'
import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail'
import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares'
import { VideoModel } from '../../../models/video/video'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
const liveRouter = express.Router()
@ -94,7 +94,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
const videoLive = new VideoLiveModel()
videoLive.saveReplay = videoInfo.saveReplay || false
videoLive.permanentLive = videoInfo.permanentLive || false
videoLive.streamKey = uuidv4()
videoLive.streamKey = buildUUID()
const [ thumbnailModel, previewModel ] = await buildVideoThumbnailsFromReq({
video,
@ -138,6 +138,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
return res.json({
video: {
id: videoCreated.id,
shortUUID: uuidToShort(videoCreated.uuid),
uuid: videoCreated.uuid
}
})

View File

@ -2,6 +2,7 @@ import * as express from 'express'
import { move } from 'fs-extra'
import { getLowercaseExtension } from '@server/helpers/core-utils'
import { deleteResumableUploadMetaFile, getResumableUploadPath } from '@server/helpers/upload'
import { uuidToShort } from '@server/helpers/uuid'
import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
import { addOptimizeOrMergeAudioJob, buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
@ -218,6 +219,7 @@ async function addVideo (options: {
return res.json({
video: {
id: videoCreated.id,
shortUUID: uuidToShort(videoCreated.uuid),
uuid: videoCreated.uuid
}
})

View File

@ -2,6 +2,7 @@ import 'multer'
import { UploadFilesForCheck } from 'express'
import { sep } from 'path'
import validator from 'validator'
import { isShortUUID, shortToUUID } from '../uuid'
function exists (value: any) {
return value !== undefined && value !== null
@ -50,42 +51,7 @@ function isIntOrNull (value: any) {
return value === null || validator.isInt('' + value)
}
function toIntOrNull (value: string) {
const v = toValueOrNull(value)
if (v === null || v === undefined) return v
if (typeof v === 'number') return v
return validator.toInt('' + v)
}
function toBooleanOrNull (value: any) {
const v = toValueOrNull(value)
if (v === null || v === undefined) return v
if (typeof v === 'boolean') return v
return validator.toBoolean('' + v)
}
function toValueOrNull (value: string) {
if (value === 'null') return null
return value
}
function toArray (value: any) {
if (value && isArray(value) === false) return [ value ]
return value
}
function toIntArray (value: any) {
if (!value) return []
if (isArray(value) === false) return [ validator.toInt(value) ]
return value.map(v => validator.toInt(v))
}
// ---------------------------------------------------------------------------
function isFileFieldValid (
files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
@ -160,6 +126,51 @@ function isFileValid (
// ---------------------------------------------------------------------------
function toCompleteUUID (value: string) {
if (isShortUUID(value)) return shortToUUID(value)
return value
}
function toIntOrNull (value: string) {
const v = toValueOrNull(value)
if (v === null || v === undefined) return v
if (typeof v === 'number') return v
return validator.toInt('' + v)
}
function toBooleanOrNull (value: any) {
const v = toValueOrNull(value)
if (v === null || v === undefined) return v
if (typeof v === 'boolean') return v
return validator.toBoolean('' + v)
}
function toValueOrNull (value: string) {
if (value === 'null') return null
return value
}
function toArray (value: any) {
if (value && isArray(value) === false) return [ value ]
return value
}
function toIntArray (value: any) {
if (!value) return []
if (isArray(value) === false) return [ validator.toInt(value) ]
return value.map(v => validator.toInt(v))
}
// ---------------------------------------------------------------------------
export {
exists,
isArrayOf,
@ -169,6 +180,7 @@ export {
isIdValid,
isSafePath,
isUUIDValid,
toCompleteUUID,
isIdOrUUIDValid,
isDateValid,
toValueOrNull,

View File

@ -1,12 +1,12 @@
import { copy, readFile, remove, rename } from 'fs-extra'
import * as Jimp from 'jimp'
import { v4 as uuidv4 } from 'uuid'
import { getLowercaseExtension } from './core-utils'
import { convertWebPToJPG, processGIF } from './ffmpeg-utils'
import { logger } from './logger'
import { buildUUID } from './uuid'
function generateImageFilename (extension = '.jpg') {
return uuidv4() + extension
return buildUUID() + extension
}
async function processImage (

32
server/helpers/uuid.ts Normal file
View File

@ -0,0 +1,32 @@
import * as short from 'short-uuid'
const translator = short()
function buildUUID () {
return short.uuid()
}
function uuidToShort (uuid: string) {
if (!uuid) return uuid
return translator.fromUUID(uuid)
}
function shortToUUID (shortUUID: string) {
if (!shortUUID) return shortUUID
return translator.toUUID(shortUUID)
}
function isShortUUID (value: string) {
if (!value) return false
return value.length === translator.maxLength
}
export {
buildUUID,
uuidToShort,
shortToUUID,
isShortUUID
}

View File

@ -1,5 +1,5 @@
import { buildUUID } from '@server/helpers/uuid'
import * as Sequelize from 'sequelize'
import { v4 as uuidv4 } from 'uuid'
async function up (utils: {
transaction: Sequelize.Transaction
@ -23,7 +23,7 @@ async function up (utils: {
{
const authors = await utils.db.Author.findAll()
for (const author of authors) {
author.uuid = uuidv4()
author.uuid = buildUUID()
await author.save()
}
}

View File

@ -1,6 +1,6 @@
import * as Sequelize from 'sequelize'
import { buildUUID } from '@server/helpers/uuid'
import { VideoPlaylistPrivacy, VideoPlaylistType } from '../../../shared/models/videos'
import { v4 as uuidv4 } from 'uuid'
import { WEBSERVER } from '../constants'
async function up (utils: {
@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS "videoPlaylistElement"
const usernames = userResult.map(r => r.username)
for (const username of usernames) {
const uuid = uuidv4()
const uuid = buildUUID()
const baseUrl = WEBSERVER.URL + '/video-playlists/' + uuid
const query = `

View File

@ -1,5 +1,5 @@
import * as Sequelize from 'sequelize'
import { v4 as uuidv4 } from 'uuid'
import { buildUUID } from '@server/helpers/uuid'
async function up (utils: {
transaction: Sequelize.Transaction
@ -26,7 +26,7 @@ async function up (utils: {
const users = await utils.sequelize.query<any>(query, options)
for (const user of users) {
const queryUpdate = `UPDATE "user" SET "feedToken" = '${uuidv4()}' WHERE id = ${user.id}`
const queryUpdate = `UPDATE "user" SET "feedToken" = '${buildUUID()}' WHERE id = ${user.id}`
await utils.sequelize.query(queryUpdate)
}
}

View File

@ -1,6 +1,6 @@
import { v4 as uuidv4 } from 'uuid'
import { getLowercaseExtension } from '@server/helpers/core-utils'
import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
import { buildUUID } from '@server/helpers/uuid'
import { MIMETYPES } from '@server/initializers/constants'
import { ActorModel } from '@server/models/actor/actor'
import { FilteredModelAttributes } from '@server/types'
@ -51,7 +51,7 @@ function getImageInfoFromObject (actorObject: ActivityPubActor, type: ActorImage
if (!extension) return undefined
return {
name: uuidv4() + extension,
name: buildUUID() + extension,
fileUrl: icon.url,
height: icon.height,
width: icon.width,

View File

@ -27,6 +27,7 @@ import { VideoChannelModel } from '../models/video/video-channel'
import { VideoPlaylistModel } from '../models/video/video-playlist'
import { MAccountActor, MChannelActor } from '../types/models'
import { ServerConfigManager } from './server-config-manager'
import { toCompleteUUID } from '@server/helpers/custom-validators/misc'
type Tags = {
ogType: string
@ -78,7 +79,9 @@ class ClientHtml {
return customHtml
}
static async getWatchHTMLPage (videoId: string, req: express.Request, res: express.Response) {
static async getWatchHTMLPage (videoIdArg: string, req: express.Request, res: express.Response) {
const videoId = toCompleteUUID(videoIdArg)
// Let Angular application handle errors
if (!validator.isInt(videoId) && !validator.isUUID(videoId, 4)) {
res.status(HttpStatusCode.NOT_FOUND_404)
@ -136,7 +139,9 @@ class ClientHtml {
return customHtml
}
static async getWatchPlaylistHTMLPage (videoPlaylistId: string, req: express.Request, res: express.Response) {
static async getWatchPlaylistHTMLPage (videoPlaylistIdArg: string, req: express.Request, res: express.Response) {
const videoPlaylistId = toCompleteUUID(videoPlaylistIdArg)
// Let Angular application handle errors
if (!validator.isInt(videoPlaylistId) && !validator.isUUID(videoPlaylistId, 4)) {
res.status(HttpStatusCode.NOT_FOUND_404)

View File

@ -2,8 +2,8 @@ import 'multer'
import { queue } from 'async'
import * as LRUCache from 'lru-cache'
import { join } from 'path'
import { v4 as uuidv4 } from 'uuid'
import { getLowercaseExtension } from '@server/helpers/core-utils'
import { buildUUID } from '@server/helpers/uuid'
import { ActorModel } from '@server/models/actor/actor'
import { ActivityPubActorType, ActorImageType } from '@shared/models'
import { retryTransactionWrapper } from '../helpers/database-utils'
@ -44,7 +44,7 @@ async function updateLocalActorImageFile (
const extension = getLowercaseExtension(imagePhysicalFile.filename)
const imageName = uuidv4() + extension
const imageName = buildUUID() + extension
const destination = join(CONFIG.STORAGE.ACTOR_IMAGES, imageName)
await processImage(imagePhysicalFile.path, destination, imageSize)

View File

@ -1,5 +1,5 @@
import { Transaction } from 'sequelize/types'
import { v4 as uuidv4 } from 'uuid'
import { buildUUID } from '@server/helpers/uuid'
import { UserModel } from '@server/models/user/user'
import { MActorDefault } from '@server/types/models/actor'
import { ActivityPubActorType } from '../../shared/models/activitypub'
@ -210,7 +210,7 @@ async function buildChannelAttributes (user: MUser, transaction?: Transaction, c
// Conflict, generate uuid instead
const actor = await ActorModel.loadLocalByName(channelName, transaction)
if (actor) channelName = uuidv4()
if (actor) channelName = buildUUID()
const videoChannelDisplayName = `Main ${user.username} channel`

View File

@ -12,7 +12,7 @@ import {
isAbuseTimestampValid,
isAbuseVideoIsValid
} from '@server/helpers/custom-validators/abuses'
import { exists, isIdOrUUIDValid, isIdValid, toIntOrNull } from '@server/helpers/custom-validators/misc'
import { exists, isIdOrUUIDValid, isIdValid, toCompleteUUID, toIntOrNull } from '@server/helpers/custom-validators/misc'
import { logger } from '@server/helpers/logger'
import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
import { AbuseCreate, UserRight } from '@shared/models'
@ -27,6 +27,7 @@ const abuseReportValidator = [
body('video.id')
.optional()
.customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid)
.withMessage('Should have a valid videoId'),
body('video.startAt')

View File

@ -1,8 +1,9 @@
import * as express from 'express'
import { param, query } from 'express-validator'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { isValidRSSFeed } from '../../helpers/custom-validators/feeds'
import { exists, isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
import { exists, isIdOrUUIDValid, isIdValid, toCompleteUUID } from '../../helpers/custom-validators/misc'
import { logger } from '../../helpers/logger'
import {
areValidationErrors,
@ -98,7 +99,10 @@ const videoSubscriptionFeedsValidator = [
]
const videoCommentsFeedsValidator = [
query('videoId').optional().custom(isIdOrUUIDValid),
query('videoId')
.customSanitizer(toCompleteUUID)
.optional()
.custom(isIdOrUUIDValid),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking feeds parameters', { parameters: req.query })

View File

@ -11,7 +11,7 @@ export * from './sort'
export * from './users'
export * from './user-subscriptions'
export * from './videos'
export * from './webfinger'
export * from './search'
export * from './server'
export * from './user-history'
export * from './webfinger'

View File

@ -6,7 +6,7 @@ import { VideoPlaylistModel } from '@server/models/video/video-playlist'
import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { isTestInstance } from '../../helpers/core-utils'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { isIdOrUUIDValid, toCompleteUUID } from '../../helpers/custom-validators/misc'
import { logger } from '../../helpers/logger'
import { WEBSERVER } from '../../initializers/constants'
import { areValidationErrors } from './shared'
@ -79,7 +79,7 @@ const oembedValidator = [
})
}
const elementId = matches[1]
const elementId = toCompleteUUID(matches[1])
if (isIdOrUUIDValid(elementId) === false) {
return res.fail({ message: 'Invalid video or playlist id.' })
}

View File

@ -2,15 +2,24 @@ import * as express from 'express'
import { body, param, query } from 'express-validator'
import { isVideoRedundancyTarget } from '@server/helpers/custom-validators/video-redundancies'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
import {
exists,
isBooleanValid,
isIdOrUUIDValid,
isIdValid,
toBooleanOrNull,
toCompleteUUID,
toIntOrNull
} from '../../helpers/custom-validators/misc'
import { isHostValid } from '../../helpers/custom-validators/servers'
import { logger } from '../../helpers/logger'
import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
import { ServerModel } from '../../models/server/server'
import { areValidationErrors, doesVideoExist } from './shared'
import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from './shared'
const videoFileRedundancyGetValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
isValidVideoIdParam('videoId'),
param('resolution')
.customSanitizer(toIntOrNull)
.custom(exists).withMessage('Should have a valid resolution'),
@ -56,9 +65,8 @@ const videoFileRedundancyGetValidator = [
]
const videoPlaylistRedundancyGetValidator = [
param('videoId')
.custom(isIdOrUUIDValid)
.not().isEmpty().withMessage('Should have a valid video id'),
isValidVideoIdParam('videoId'),
param('streamingPlaylistType')
.customSanitizer(toIntOrNull)
.custom(exists).withMessage('Should have a valid streaming playlist type'),
@ -135,7 +143,8 @@ const listVideoRedundanciesValidator = [
const addVideoRedundancyValidator = [
body('videoId')
.custom(isIdValid)
.customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid)
.withMessage('Should have a valid video id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {

View File

@ -1,5 +1,6 @@
import * as express from 'express'
import { query, validationResult } from 'express-validator'
import { param, query, validationResult } from 'express-validator'
import { isIdOrUUIDValid, toCompleteUUID } from '@server/helpers/custom-validators/misc'
import { logger } from '../../../helpers/logger'
function areValidationErrors (req: express.Request, res: express.Response) {
@ -41,10 +42,24 @@ function createSortableColumns (sortableColumns: string[]) {
return sortableColumns.concat(sortableColumnDesc)
}
function isValidVideoIdParam (paramName: string) {
return param(paramName)
.customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid).withMessage('Should have a valid video id')
}
function isValidPlaylistIdParam (paramName: string) {
return param(paramName)
.customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id')
}
// ---------------------------------------------------------------------------
export {
areValidationErrors,
checkSort,
createSortableColumns
createSortableColumns,
isValidVideoIdParam,
isValidPlaylistIdParam
}

View File

@ -7,7 +7,7 @@ import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-code
import { UserRole } from '../../../shared/models/users'
import { UserRegister } from '../../../shared/models/users/user-register.model'
import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
import { isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
import { toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
import {
isNoInstanceConfigWarningModal,
@ -35,7 +35,7 @@ import { Redis } from '../../lib/redis'
import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup'
import { ActorModel } from '../../models/actor/actor'
import { UserModel } from '../../models/user/user'
import { areValidationErrors, doesVideoExist } from './shared'
import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from './shared'
const usersListValidator = [
query('blocked')
@ -302,7 +302,7 @@ const usersGetValidator = [
]
const usersVideoRatingValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking usersVideoRating parameters', { parameters: req.params })

View File

@ -1,13 +1,13 @@
import * as express from 'express'
import { body, param, query } from 'express-validator'
import { body, query } from 'express-validator'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { isBooleanValid, isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
import { isBooleanValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../../helpers/custom-validators/video-blacklist'
import { logger } from '../../../helpers/logger'
import { areValidationErrors, doesVideoBlacklistExist, doesVideoExist } from '../shared'
import { areValidationErrors, doesVideoBlacklistExist, doesVideoExist, isValidVideoIdParam } from '../shared'
const videosBlacklistRemoveValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
@ -21,7 +21,8 @@ const videosBlacklistRemoveValidator = [
]
const videosBlacklistAddValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
body('unfederate')
.optional()
.customSanitizer(toBooleanOrNull)
@ -49,7 +50,8 @@ const videosBlacklistAddValidator = [
]
const videosBlacklistUpdateValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
body('reason')
.optional()
.custom(isVideoBlacklistReasonValid).withMessage('Should have a valid reason'),

View File

@ -1,16 +1,18 @@
import * as express from 'express'
import { body, param } from 'express-validator'
import { UserRight } from '../../../../shared'
import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc'
import { isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions'
import { cleanUpReqFiles } from '../../../helpers/express-utils'
import { logger } from '../../../helpers/logger'
import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../../initializers/constants'
import { areValidationErrors, checkUserCanManageVideo, doesVideoCaptionExist, doesVideoExist } from '../shared'
import { areValidationErrors, checkUserCanManageVideo, doesVideoCaptionExist, doesVideoExist, isValidVideoIdParam } from '../shared'
const addVideoCaptionValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
isValidVideoIdParam('videoId'),
param('captionLanguage')
.custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
body('captionfile')
.custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
.withMessage(
@ -34,8 +36,10 @@ const addVideoCaptionValidator = [
]
const deleteVideoCaptionValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
isValidVideoIdParam('videoId'),
param('captionLanguage')
.custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params })
@ -53,7 +57,7 @@ const deleteVideoCaptionValidator = [
]
const listVideoCaptionsValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking listVideoCaptions parameters', { parameters: req.params })

View File

@ -3,13 +3,13 @@ import { body, param, query } from 'express-validator'
import { MUserAccountUrl } from '@server/types/models'
import { UserRight } from '../../../../shared'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
import { logger } from '../../../helpers/logger'
import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
import { Hooks } from '../../../lib/plugins/hooks'
import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video'
import { areValidationErrors, doesVideoCommentExist, doesVideoCommentThreadExist, doesVideoExist } from '../shared'
import { areValidationErrors, doesVideoCommentExist, doesVideoCommentThreadExist, doesVideoExist, isValidVideoIdParam } from '../shared'
const listVideoCommentsValidator = [
query('isLocal')
@ -40,7 +40,7 @@ const listVideoCommentsValidator = [
]
const listVideoCommentThreadsValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
@ -53,8 +53,10 @@ const listVideoCommentThreadsValidator = [
]
const listVideoThreadCommentsValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
isValidVideoIdParam('videoId'),
param('threadId')
.custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
@ -68,8 +70,10 @@ const listVideoThreadCommentsValidator = [
]
const addVideoCommentThreadValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
isValidVideoIdParam('videoId'),
body('text')
.custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
@ -84,8 +88,10 @@ const addVideoCommentThreadValidator = [
]
const addVideoCommentReplyValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@ -102,8 +108,10 @@ const addVideoCommentReplyValidator = [
]
const videoCommentGetValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
isValidVideoIdParam('videoId'),
param('commentId')
.custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
@ -117,7 +125,8 @@ const videoCommentGetValidator = [
]
const removeVideoCommentValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {

View File

@ -1,5 +1,5 @@
import * as express from 'express'
import { body, param } from 'express-validator'
import { body } from 'express-validator'
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
import { isLocalLiveVideoAccepted } from '@server/lib/moderation'
import { Hooks } from '@server/lib/plugins/hooks'
@ -7,16 +7,22 @@ import { VideoModel } from '@server/models/video/video'
import { VideoLiveModel } from '@server/models/video/video-live'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { ServerErrorCode, UserRight, VideoState } from '@shared/models'
import { isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
import { isVideoNameValid } from '../../../helpers/custom-validators/videos'
import { cleanUpReqFiles } from '../../../helpers/express-utils'
import { logger } from '../../../helpers/logger'
import { CONFIG } from '../../../initializers/config'
import { areValidationErrors, checkUserCanManageVideo, doesVideoChannelOfAccountExist, doesVideoExist } from '../shared'
import {
areValidationErrors,
checkUserCanManageVideo,
doesVideoChannelOfAccountExist,
doesVideoExist,
isValidVideoIdParam
} from '../shared'
import { getCommonVideoEditAttributes } from './videos'
const videoLiveGetValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params, user: res.locals.oauth.token.User.username })

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { param } from 'express-validator'
import { isIdOrUUIDValid } from '@server/helpers/custom-validators/misc'
import { isIdValid } from '@server/helpers/custom-validators/misc'
import { checkUserCanTerminateOwnershipChange } from '@server/helpers/custom-validators/video-ownership'
import { logger } from '@server/helpers/logger'
import { isAbleToUploadVideo } from '@server/lib/user'
@ -13,11 +13,12 @@ import {
checkUserCanManageVideo,
doesChangeVideoOwnershipExist,
doesVideoChannelOfAccountExist,
doesVideoExist
doesVideoExist,
isValidVideoIdParam
} from '../shared'
const videosChangeOwnershipValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('videoId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking changeOwnership parameters', { parameters: req.params })
@ -40,7 +41,8 @@ const videosChangeOwnershipValidator = [
]
const videosTerminateChangeOwnershipValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
param('id')
.custom(isIdValid).withMessage('Should have a valid id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking changeOwnership parameters', { parameters: req.params })

View File

@ -11,6 +11,7 @@ import {
isIdOrUUIDValid,
isIdValid,
isUUIDValid,
toCompleteUUID,
toIntArray,
toIntOrNull,
toValueOrNull
@ -29,7 +30,14 @@ import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element'
import { MVideoPlaylist } from '../../../types/models/video/video-playlist'
import { authenticatePromiseIfNeeded } from '../../auth'
import { areValidationErrors, doesVideoChannelIdExist, doesVideoExist, doesVideoPlaylistExist, VideoPlaylistFetchType } from '../shared'
import {
areValidationErrors,
doesVideoChannelIdExist,
doesVideoExist,
doesVideoPlaylistExist,
isValidPlaylistIdParam,
VideoPlaylistFetchType
} from '../shared'
const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
body('displayName')
@ -43,10 +51,13 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
const body: VideoPlaylistCreate = req.body
if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req)
if (body.privacy === VideoPlaylistPrivacy.PUBLIC && !body.videoChannelId) {
if (
!body.videoChannelId &&
(body.privacy === VideoPlaylistPrivacy.PUBLIC || body.privacy === VideoPlaylistPrivacy.UNLISTED)
) {
cleanUpReqFiles(req)
return res.fail({ message: 'Cannot set "public" a playlist that is not assigned to a channel.' })
return res.fail({ message: 'Cannot set "public" or "unlisted" a playlist that is not assigned to a channel.' })
}
return next()
@ -54,8 +65,7 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
])
const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
body('displayName')
.optional()
@ -101,8 +111,7 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
])
const videoPlaylistsDeleteValidator = [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoPlaylistsDeleteValidator parameters', { parameters: req.params })
@ -126,8 +135,7 @@ const videoPlaylistsDeleteValidator = [
const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => {
return [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoPlaylistsGetValidator parameters', { parameters: req.params })
@ -184,9 +192,10 @@ const videoPlaylistsSearchValidator = [
]
const videoPlaylistsAddVideoValidator = [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
body('videoId')
.customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'),
body('startTimestamp')
.optional()
@ -214,9 +223,9 @@ const videoPlaylistsAddVideoValidator = [
]
const videoPlaylistsUpdateOrRemoveVideoValidator = [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
param('playlistElementId')
.customSanitizer(toCompleteUUID)
.custom(isIdValid).withMessage('Should have an element id/uuid'),
body('startTimestamp')
.optional()
@ -251,8 +260,7 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
]
const videoPlaylistElementAPGetValidator = [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
param('playlistElementId')
.custom(isIdValid).withMessage('Should have an playlist element id'),
@ -287,8 +295,7 @@ const videoPlaylistElementAPGetValidator = [
]
const videoPlaylistsReorderVideosValidator = [
param('playlistId')
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
isValidPlaylistIdParam('playlistId'),
body('startPosition')
.isInt({ min: 1 }).withMessage('Should have a valid start position'),
body('insertAfterPosition')

View File

@ -3,15 +3,16 @@ import { body, param, query } from 'express-validator'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { VideoRateType } from '../../../../shared/models/videos'
import { isAccountNameValid } from '../../../helpers/custom-validators/accounts'
import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
import { isIdValid } from '../../../helpers/custom-validators/misc'
import { isRatingValid } from '../../../helpers/custom-validators/video-rates'
import { isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos'
import { logger } from '../../../helpers/logger'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { areValidationErrors, doesVideoExist } from '../shared'
import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
const videoUpdateRateValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('id'),
body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {

View File

@ -1,14 +1,16 @@
import * as express from 'express'
import { param } from 'express-validator'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
import { isIdValid } from '../../../helpers/custom-validators/misc'
import { logger } from '../../../helpers/logger'
import { VideoShareModel } from '../../../models/video/video-share'
import { areValidationErrors, doesVideoExist } from '../shared'
import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
const videosShareValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
param('actorId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid actor id'),
isValidVideoIdParam('id'),
param('actorId')
.custom(isIdValid).not().isEmpty().withMessage('Should have a valid actor id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoShare parameters', { parameters: req.params })

View File

@ -1,12 +1,13 @@
import * as express from 'express'
import { body, param } from 'express-validator'
import { body } from 'express-validator'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { isIdOrUUIDValid, toIntOrNull } from '../../../helpers/custom-validators/misc'
import { toIntOrNull } from '../../../helpers/custom-validators/misc'
import { logger } from '../../../helpers/logger'
import { areValidationErrors, doesVideoExist } from '../shared'
import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
const videoWatchingValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('videoId'),
body('currentTime')
.customSanitizer(toIntOrNull)
.isInt().withMessage('Should have correct current time'),

View File

@ -12,7 +12,6 @@ import {
isBooleanValid,
isDateValid,
isFileFieldValid,
isIdOrUUIDValid,
isIdValid,
isUUIDValid,
toArray,
@ -53,7 +52,8 @@ import {
checkUserCanManageVideo,
doesVideoChannelOfAccountExist,
doesVideoExist,
doesVideoFileOfVideoExist
doesVideoFileOfVideoExist,
isValidVideoIdParam
} from '../shared'
const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
@ -195,7 +195,8 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
])
const videosUpdateValidator = getCommonVideoEditAttributes().concat([
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('id'),
body('name')
.optional()
.trim()
@ -258,7 +259,7 @@ const videosCustomGetValidator = (
authenticateInQuery = false
) => {
return [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videosGet parameters', { parameters: req.params })
@ -309,8 +310,10 @@ const videosGetValidator = videosCustomGetValidator('all')
const videosDownloadValidator = videosCustomGetValidator('all', true)
const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
param('videoFileId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'),
isValidVideoIdParam('id'),
param('videoFileId')
.custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params })
@ -323,7 +326,7 @@ const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
])
const videosRemoveValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
isValidVideoIdParam('id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videosRemove parameters', { parameters: req.params })

View File

@ -1,3 +1,4 @@
import { uuidToShort } from '@server/helpers/uuid'
import { generateMagnetUri } from '@server/helpers/webtorrent'
import { getLocalVideoFileMetadataUrl } from '@server/lib/video-paths'
import { VideoFile } from '@shared/models/videos/video-file.model'
@ -47,6 +48,8 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor
const videoObject: Video = {
id: video.id,
uuid: video.uuid,
shortUUID: uuidToShort(video.uuid),
name: video.name,
category: {
id: video.category,

View File

@ -15,7 +15,7 @@ import {
Table,
UpdatedAt
} from 'sequelize-typescript'
import { v4 as uuidv4 } from 'uuid'
import { buildUUID } from '@server/helpers/uuid'
import { MVideo, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models'
import { AttributesOnly } from '@shared/core-utils'
import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model'
@ -182,7 +182,7 @@ export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaption
}
static generateCaptionName (language: string) {
return `${uuidv4()}-${language}.vtt`
return `${buildUUID()}-${language}.vtt`
}
isOwned () {

View File

@ -17,8 +17,8 @@ import {
Table,
UpdatedAt
} from 'sequelize-typescript'
import { v4 as uuidv4 } from 'uuid'
import { setAsUpdated } from '@server/helpers/database-utils'
import { buildUUID, uuidToShort } from '@server/helpers/uuid'
import { MAccountId, MChannelId } from '@server/types/models'
import { AttributesOnly } from '@shared/core-utils'
import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
@ -545,7 +545,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
generateThumbnailName () {
const extension = '.jpg'
return 'playlist-' + uuidv4() + extension
return 'playlist-' + buildUUID() + extension
}
getThumbnailUrl () {
@ -617,6 +617,8 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
return {
id: this.id,
uuid: this.uuid,
shortUUID: uuidToShort(this.uuid),
isLocal: this.isOwned(),
url: this.url,

View File

@ -1,23 +1,65 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import * as chai from 'chai'
import { VideoPlaylistPrivacy } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
cleanupTests,
createVideoPlaylist,
doubleFollow,
flushAndRunMultipleServers,
makeActivityPubGetRequest,
ServerInfo,
setAccessTokensToServers,
uploadVideo
setDefaultVideoChannel,
uploadVideoAndGetId
} from '../../../../shared/extra-utils'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
const expect = chai.expect
describe('Test activitypub', function () {
let servers: ServerInfo[] = []
let videoUUID: string
let video: { id: number, uuid: string, shortUUID: string }
let playlist: { id: number, uuid: string, shortUUID: string }
async function testAccount (path: string) {
const res = await makeActivityPubGetRequest(servers[0].url, path)
const object = res.body
expect(object.type).to.equal('Person')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root')
expect(object.name).to.equal('root')
expect(object.preferredUsername).to.equal('root')
}
async function testChannel (path: string) {
const res = await makeActivityPubGetRequest(servers[0].url, path)
const object = res.body
expect(object.type).to.equal('Group')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/video-channels/root_channel')
expect(object.name).to.equal('Main root channel')
expect(object.preferredUsername).to.equal('root_channel')
}
async function testVideo (path: string) {
const res = await makeActivityPubGetRequest(servers[0].url, path)
const object = res.body
expect(object.type).to.equal('Video')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + video.uuid)
expect(object.name).to.equal('video')
}
async function testPlaylist (path: string) {
const res = await makeActivityPubGetRequest(servers[0].url, path)
const object = res.body
expect(object.type).to.equal('Playlist')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/video-playlists/' + playlist.uuid)
expect(object.name).to.equal('playlist')
}
before(async function () {
this.timeout(30000)
@ -25,38 +67,56 @@ describe('Test activitypub', function () {
servers = await flushAndRunMultipleServers(2)
await setAccessTokensToServers(servers)
await setDefaultVideoChannel(servers)
{
const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
videoUUID = res.body.video.uuid
video = await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })
}
{
const playlistAttrs = { displayName: 'playlist', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[0].videoChannel.id }
const resCreate = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
playlist = resCreate.body.videoPlaylist
}
await doubleFollow(servers[0], servers[1])
})
it('Should return the account object', async function () {
const res = await makeActivityPubGetRequest(servers[0].url, '/accounts/root')
const object = res.body
await testAccount('/accounts/root')
await testAccount('/a/root')
})
expect(object.type).to.equal('Person')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root')
expect(object.name).to.equal('root')
expect(object.preferredUsername).to.equal('root')
it('Should return the channel object', async function () {
await testChannel('/video-channels/root_channel')
await testChannel('/c/root_channel')
})
it('Should return the video object', async function () {
const res = await makeActivityPubGetRequest(servers[0].url, '/videos/watch/' + videoUUID)
const object = res.body
await testVideo('/videos/watch/' + video.id)
await testVideo('/videos/watch/' + video.uuid)
await testVideo('/videos/watch/' + video.shortUUID)
await testVideo('/w/' + video.id)
await testVideo('/w/' + video.uuid)
await testVideo('/w/' + video.shortUUID)
})
expect(object.type).to.equal('Video')
expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
expect(object.name).to.equal('video')
it('Should return the playlist object', async function () {
await testPlaylist('/video-playlists/' + playlist.id)
await testPlaylist('/video-playlists/' + playlist.uuid)
await testPlaylist('/video-playlists/' + playlist.shortUUID)
await testPlaylist('/w/p/' + playlist.id)
await testPlaylist('/w/p/' + playlist.uuid)
await testPlaylist('/w/p/' + playlist.shortUUID)
await testPlaylist('/videos/watch/playlist/' + playlist.id)
await testPlaylist('/videos/watch/playlist/' + playlist.uuid)
await testPlaylist('/videos/watch/playlist/' + playlist.shortUUID)
})
it('Should redirect to the origin video object', async function () {
const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, HttpStatusCode.FOUND_302)
const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + video.uuid, HttpStatusCode.FOUND_302)
expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + video.uuid)
})
after(async function () {

View File

@ -258,7 +258,7 @@ describe('Test abuses API validators', function () {
})
it('Should succeed with the correct parameters (basic)', async function () {
const fields: AbuseCreate = { video: { id: server.video.id }, reason: 'my super reason' }
const fields: AbuseCreate = { video: { id: server.video.shortUUID }, reason: 'my super reason' }
const res = await makePostBodyRequest({
url: server.url,

View File

@ -2,7 +2,7 @@
import 'mocha'
import { omit } from 'lodash'
import { LiveVideo, VideoPrivacy } from '@shared/models'
import { LiveVideo, VideoCreateResult, VideoPrivacy } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
buildAbsoluteFixturePath,
@ -31,7 +31,7 @@ describe('Test video lives API validator', function () {
let server: ServerInfo
let userAccessToken = ''
let channelId: number
let videoId: number
let video: VideoCreateResult
let videoIdNotLive: number
// ---------------------------------------------------------------
@ -230,7 +230,7 @@ describe('Test video lives API validator', function () {
statusCodeExpected: HttpStatusCode.OK_200
})
videoId = res.body.video.id
video = res.body.video
})
it('Should forbid if live is disabled', async function () {
@ -326,15 +326,15 @@ describe('Test video lives API validator', function () {
describe('When getting live information', function () {
it('Should fail without access token', async function () {
await getLive(server.url, '', videoId, HttpStatusCode.UNAUTHORIZED_401)
await getLive(server.url, '', video.id, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should fail with a bad access token', async function () {
await getLive(server.url, 'toto', videoId, HttpStatusCode.UNAUTHORIZED_401)
await getLive(server.url, 'toto', video.id, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should fail with access token of another user', async function () {
await getLive(server.url, userAccessToken, videoId, HttpStatusCode.FORBIDDEN_403)
await getLive(server.url, userAccessToken, video.id, HttpStatusCode.FORBIDDEN_403)
})
it('Should fail with a bad video id', async function () {
@ -350,22 +350,23 @@ describe('Test video lives API validator', function () {
})
it('Should succeed with the correct params', async function () {
await getLive(server.url, server.accessToken, videoId)
await getLive(server.url, server.accessToken, video.id)
await getLive(server.url, server.accessToken, video.shortUUID)
})
})
describe('When updating live information', async function () {
it('Should fail without access token', async function () {
await updateLive(server.url, '', videoId, {}, HttpStatusCode.UNAUTHORIZED_401)
await updateLive(server.url, '', video.id, {}, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should fail with a bad access token', async function () {
await updateLive(server.url, 'toto', videoId, {}, HttpStatusCode.UNAUTHORIZED_401)
await updateLive(server.url, 'toto', video.id, {}, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should fail with access token of another user', async function () {
await updateLive(server.url, userAccessToken, videoId, {}, HttpStatusCode.FORBIDDEN_403)
await updateLive(server.url, userAccessToken, video.id, {}, HttpStatusCode.FORBIDDEN_403)
})
it('Should fail with a bad video id', async function () {
@ -383,11 +384,12 @@ describe('Test video lives API validator', function () {
it('Should fail with save replay and permanent live set to true', async function () {
const fields = { saveReplay: true, permanentLive: true }
await updateLive(server.url, server.accessToken, videoId, fields, HttpStatusCode.BAD_REQUEST_400)
await updateLive(server.url, server.accessToken, video.id, fields, HttpStatusCode.BAD_REQUEST_400)
})
it('Should succeed with the correct params', async function () {
await updateLive(server.url, server.accessToken, videoId, { saveReplay: false })
await updateLive(server.url, server.accessToken, video.id, { saveReplay: false })
await updateLive(server.url, server.accessToken, video.shortUUID, { saveReplay: false })
})
it('Should fail to update replay status if replay is not allowed on the instance', async function () {
@ -398,19 +400,19 @@ describe('Test video lives API validator', function () {
}
})
await updateLive(server.url, server.accessToken, videoId, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403)
await updateLive(server.url, server.accessToken, video.id, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403)
})
it('Should fail to update a live if it has already started', async function () {
this.timeout(40000)
const resLive = await getLive(server.url, server.accessToken, videoId)
const resLive = await getLive(server.url, server.accessToken, video.id)
const live: LiveVideo = resLive.body
const command = sendRTMPStream(live.rtmpUrl, live.streamKey)
await waitUntilLivePublished(server.url, server.accessToken, videoId)
await updateLive(server.url, server.accessToken, videoId, {}, HttpStatusCode.BAD_REQUEST_400)
await waitUntilLivePublished(server.url, server.accessToken, video.id)
await updateLive(server.url, server.accessToken, video.id, {}, HttpStatusCode.BAD_REQUEST_400)
await stopFfmpeg(command)
})
@ -418,14 +420,14 @@ describe('Test video lives API validator', function () {
it('Should fail to stream twice in the save live', async function () {
this.timeout(40000)
const resLive = await getLive(server.url, server.accessToken, videoId)
const resLive = await getLive(server.url, server.accessToken, video.id)
const live: LiveVideo = resLive.body
const command = sendRTMPStream(live.rtmpUrl, live.streamKey)
await waitUntilLivePublished(server.url, server.accessToken, videoId)
await waitUntilLivePublished(server.url, server.accessToken, video.id)
await runAndTestFfmpegStreamError(server.url, server.accessToken, videoId, true)
await runAndTestFfmpegStreamError(server.url, server.accessToken, video.id, true)
await stopFfmpeg(command)
})

View File

@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { VideoCreateResult } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
checkBadCountPagination,
checkBadSortPagination,
@ -9,20 +10,24 @@ import {
cleanupTests,
createUser,
doubleFollow,
flushAndRunMultipleServers, makeDeleteRequest,
makeGetRequest, makePostBodyRequest,
flushAndRunMultipleServers,
getVideo,
makeDeleteRequest,
makeGetRequest,
makePostBodyRequest,
makePutBodyRequest,
ServerInfo,
setAccessTokensToServers, uploadVideoAndGetId,
userLogin, waitJobs, getVideoIdFromUUID
setAccessTokensToServers,
uploadVideoAndGetId,
userLogin,
waitJobs
} from '../../../../shared/extra-utils'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
describe('Test server redundancy API validators', function () {
let servers: ServerInfo[]
let userAccessToken = null
let videoIdLocal: number
let videoIdRemote: number
let videoRemote: VideoCreateResult
// ---------------------------------------------------------------
@ -48,7 +53,8 @@ describe('Test server redundancy API validators', function () {
await waitJobs(servers)
videoIdRemote = await getVideoIdFromUUID(servers[0].url, remoteUUID)
const resVideo = await getVideo(servers[0].url, remoteUUID)
videoRemote = resVideo.body
})
describe('When listing redundancies', function () {
@ -131,7 +137,13 @@ describe('Test server redundancy API validators', function () {
})
it('Should succeed with the correct params', async function () {
await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 })
await makePostBodyRequest({
url,
path,
token,
fields: { videoId: videoRemote.shortUUID },
statusCodeExpected: HttpStatusCode.NO_CONTENT_204
})
})
it('Should fail if the video is already duplicated', async function () {
@ -139,7 +151,13 @@ describe('Test server redundancy API validators', function () {
await waitJobs(servers)
await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: HttpStatusCode.CONFLICT_409 })
await makePostBodyRequest({
url,
path,
token,
fields: { videoId: videoRemote.uuid },
statusCodeExpected: HttpStatusCode.CONFLICT_409
})
})
})

View File

@ -2,7 +2,7 @@
import 'mocha'
import { omit } from 'lodash'
import { User, UserRole } from '../../../../shared'
import { User, UserRole, VideoCreateResult } from '../../../../shared'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
addVideoChannel,
@ -45,7 +45,7 @@ describe('Test users API validators', function () {
let userId: number
let rootId: number
let moderatorId: number
let videoId: number
let video: VideoCreateResult
let server: ServerInfo
let serverWithRegistrationDisabled: ServerInfo
let userAccessToken = ''
@ -126,7 +126,7 @@ describe('Test users API validators', function () {
{
const res = await uploadVideo(server.url, server.accessToken, {})
videoId = res.body.video.id
video = res.body.video
}
{
@ -829,7 +829,7 @@ describe('Test users API validators', function () {
describe('When getting my video rating', function () {
it('Should fail with a non authenticated user', async function () {
await getMyUserVideoRating(server.url, 'fake_token', videoId, HttpStatusCode.UNAUTHORIZED_401)
await getMyUserVideoRating(server.url, 'fake_token', video.id, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should fail with an incorrect video uuid', async function () {
@ -841,7 +841,9 @@ describe('Test users API validators', function () {
})
it('Should succeed with the correct parameters', async function () {
await getMyUserVideoRating(server.url, server.accessToken, videoId)
await getMyUserVideoRating(server.url, server.accessToken, video.id)
await getMyUserVideoRating(server.url, server.accessToken, video.uuid)
await getMyUserVideoRating(server.url, server.accessToken, video.shortUUID)
})
})

View File

@ -191,7 +191,7 @@ describe('Test video blacklist API validators', function () {
})
it('Should succeed with the correct params', async function () {
const path = basePath + servers[0].video.uuid + '/blacklist'
const path = basePath + servers[0].video.shortUUID + '/blacklist'
const fields = { reason: 'hello' }
await makePutBodyRequest({
@ -222,10 +222,14 @@ describe('Test video blacklist API validators', function () {
})
it('Should succeed with an admin', async function () {
const res = await getVideoWithToken(servers[0].url, servers[0].accessToken, servers[0].video.uuid, HttpStatusCode.OK_200)
const video: VideoDetails = res.body
const video = servers[0].video
expect(video.blacklisted).to.be.true
for (const id of [ video.id, video.uuid, video.shortUUID ]) {
const res = await getVideoWithToken(servers[0].url, servers[0].accessToken, id, HttpStatusCode.OK_200)
const video: VideoDetails = res.body
expect(video.blacklisted).to.be.true
}
})
})

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { VideoCreateResult } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
buildAbsoluteFixturePath,
@ -23,7 +23,7 @@ describe('Test video captions API validator', function () {
let server: ServerInfo
let userAccessToken: string
let videoUUID: string
let video: VideoCreateResult
// ---------------------------------------------------------------
@ -36,7 +36,7 @@ describe('Test video captions API validator', function () {
{
const res = await uploadVideo(server.url, server.accessToken, {})
videoUUID = res.body.video.uuid
video = res.body.video
}
{
@ -79,7 +79,7 @@ describe('Test video captions API validator', function () {
})
it('Should fail with a missing language in path', async function () {
const captionPath = path + videoUUID + '/captions'
const captionPath = path + video.uuid + '/captions'
await makeUploadRequest({
method: 'PUT',
url: server.url,
@ -91,7 +91,7 @@ describe('Test video captions API validator', function () {
})
it('Should fail with an unknown language', async function () {
const captionPath = path + videoUUID + '/captions/15'
const captionPath = path + video.uuid + '/captions/15'
await makeUploadRequest({
method: 'PUT',
url: server.url,
@ -103,7 +103,7 @@ describe('Test video captions API validator', function () {
})
it('Should fail without access token', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.uuid + '/captions/fr'
await makeUploadRequest({
method: 'PUT',
url: server.url,
@ -115,7 +115,7 @@ describe('Test video captions API validator', function () {
})
it('Should fail with a bad access token', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.uuid + '/captions/fr'
await makeUploadRequest({
method: 'PUT',
url: server.url,
@ -133,7 +133,7 @@ describe('Test video captions API validator', function () {
// 'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt')
// }
//
// const captionPath = path + videoUUID + '/captions/fr'
// const captionPath = path + video.uuid + '/captions/fr'
// await makeUploadRequest({
// method: 'PUT',
// url: server.url,
@ -151,7 +151,7 @@ describe('Test video captions API validator', function () {
// url: server.url,
// accessToken: server.accessToken,
// language: 'zh',
// videoId: videoUUID,
// videoId: video.uuid,
// fixture: 'subtitle-bad.txt',
// mimeType: 'application/octet-stream',
// statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
@ -163,7 +163,7 @@ describe('Test video captions API validator', function () {
url: server.url,
accessToken: server.accessToken,
language: 'zh',
videoId: videoUUID,
videoId: video.uuid,
fixture: 'subtitle-good.srt',
mimeType: 'application/octet-stream'
})
@ -175,7 +175,7 @@ describe('Test video captions API validator', function () {
// 'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt')
// }
//
// const captionPath = path + videoUUID + '/captions/fr'
// const captionPath = path + video.uuid + '/captions/fr'
// await makeUploadRequest({
// method: 'PUT',
// url: server.url,
@ -188,7 +188,7 @@ describe('Test video captions API validator', function () {
// })
it('Should success with the correct parameters', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.uuid + '/captions/fr'
await makeUploadRequest({
method: 'PUT',
url: server.url,
@ -215,7 +215,7 @@ describe('Test video captions API validator', function () {
})
it('Should success with the correct parameters', async function () {
await makeGetRequest({ url: server.url, path: path + videoUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 })
await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 })
})
})
@ -246,27 +246,27 @@ describe('Test video captions API validator', function () {
})
it('Should fail with a missing language', async function () {
const captionPath = path + videoUUID + '/captions'
const captionPath = path + video.shortUUID + '/captions'
await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
})
it('Should fail with an unknown language', async function () {
const captionPath = path + videoUUID + '/captions/15'
const captionPath = path + video.shortUUID + '/captions/15'
await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
})
it('Should fail without access token', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.shortUUID + '/captions/fr'
await makeDeleteRequest({ url: server.url, path: captionPath, statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 })
})
it('Should fail with a bad access token', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.shortUUID + '/captions/fr'
await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 })
})
it('Should fail with another user', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.shortUUID + '/captions/fr'
await makeDeleteRequest({
url: server.url,
path: captionPath,
@ -276,7 +276,7 @@ describe('Test video captions API validator', function () {
})
it('Should success with the correct parameters', async function () {
const captionPath = path + videoUUID + '/captions/fr'
const captionPath = path + video.shortUUID + '/captions/fr'
await makeDeleteRequest({
url: server.url,
path: captionPath,

View File

@ -1,7 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import * as chai from 'chai'
import { VideoCreateResult } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
cleanupTests,
createUser,
@ -20,7 +22,6 @@ import {
checkBadStartPagination
} from '../../../../shared/extra-utils/requests/check-api-params'
import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
const expect = chai.expect
@ -28,7 +29,7 @@ describe('Test video comments API validator', function () {
let pathThread: string
let pathComment: string
let server: ServerInfo
let videoUUID: string
let video: VideoCreateResult
let userAccessToken: string
let userAccessToken2: string
let commentId: number
@ -44,14 +45,14 @@ describe('Test video comments API validator', function () {
{
const res = await uploadVideo(server.url, server.accessToken, {})
videoUUID = res.body.video.uuid
pathThread = '/api/v1/videos/' + videoUUID + '/comment-threads'
video = res.body.video
pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
}
{
const res = await addVideoCommentThread(server.url, server.accessToken, videoUUID, 'coucou')
const res = await addVideoCommentThread(server.url, server.accessToken, video.uuid, 'coucou')
commentId = res.body.comment.id
pathComment = '/api/v1/videos/' + videoUUID + '/comments/' + commentId
pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId
}
{
@ -101,7 +102,7 @@ describe('Test video comments API validator', function () {
it('Should fail with an incorrect thread id', async function () {
await makeGetRequest({
url: server.url,
path: '/api/v1/videos/' + videoUUID + '/comment-threads/156',
path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/156',
statusCodeExpected: HttpStatusCode.NOT_FOUND_404
})
})
@ -109,7 +110,7 @@ describe('Test video comments API validator', function () {
it('Should success with the correct params', async function () {
await makeGetRequest({
url: server.url,
path: '/api/v1/videos/' + videoUUID + '/comment-threads/' + commentId,
path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/' + commentId,
statusCodeExpected: HttpStatusCode.OK_200
})
})
@ -225,7 +226,7 @@ describe('Test video comments API validator', function () {
})
it('Should fail with an incorrect comment', async function () {
const path = '/api/v1/videos/' + videoUUID + '/comments/124'
const path = '/api/v1/videos/' + video.uuid + '/comments/124'
const fields = {
text: 'super comment'
}
@ -272,7 +273,7 @@ describe('Test video comments API validator', function () {
})
it('Should fail with an incorrect comment', async function () {
const path = '/api/v1/videos/' + videoUUID + '/comments/124'
const path = '/api/v1/videos/' + video.uuid + '/comments/124'
await makeDeleteRequest({ url: server.url, path, token: server.accessToken, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
})
@ -280,11 +281,11 @@ describe('Test video comments API validator', function () {
let commentToDelete: number
{
const res = await addVideoCommentThread(server.url, userAccessToken, videoUUID, 'hello')
const res = await addVideoCommentThread(server.url, userAccessToken, video.uuid, 'hello')
commentToDelete = res.body.comment.id
}
const path = '/api/v1/videos/' + videoUUID + '/comments/' + commentToDelete
const path = '/api/v1/videos/' + video.uuid + '/comments/' + commentToDelete
await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
await makeDeleteRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 })
@ -323,8 +324,8 @@ describe('Test video comments API validator', function () {
describe('When a video has comments disabled', function () {
before(async function () {
const res = await uploadVideo(server.url, server.accessToken, { commentsEnabled: false })
videoUUID = res.body.video.uuid
pathThread = '/api/v1/videos/' + videoUUID + '/comment-threads'
video = res.body.video
pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
})
it('Should return an empty thread list', async function () {

View File

@ -1,8 +1,13 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { VideoPlaylistCreateResult, VideoPlaylistPrivacy, VideoPlaylistType } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
addVideoInPlaylist,
checkBadCountPagination,
checkBadSortPagination,
checkBadStartPagination,
cleanupTests,
createVideoPlaylist,
deleteVideoPlaylist,
@ -21,20 +26,14 @@ import {
updateVideoPlaylistElement,
uploadVideoAndGetId
} from '../../../../shared/extra-utils'
import {
checkBadCountPagination,
checkBadSortPagination,
checkBadStartPagination
} from '../../../../shared/extra-utils/requests/check-api-params'
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
describe('Test video playlists API validator', function () {
let server: ServerInfo
let userAccessToken: string
let playlistUUID: string
let playlist: VideoPlaylistCreateResult
let privatePlaylistUUID: string
let watchLaterPlaylistId: number
let videoId: number
let playlistElementId: number
@ -67,7 +66,7 @@ describe('Test video playlists API validator', function () {
videoChannelId: server.videoChannel.id
}
})
playlistUUID = res.body.videoPlaylist.uuid
playlist = res.body.videoPlaylist
}
{
@ -150,15 +149,15 @@ describe('Test video playlists API validator', function () {
const path = '/api/v1/video-playlists/'
it('Should fail with a bad start pagination', async function () {
await checkBadStartPagination(server.url, path + playlistUUID + '/videos', server.accessToken)
await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
})
it('Should fail with a bad count pagination', async function () {
await checkBadCountPagination(server.url, path + playlistUUID + '/videos', server.accessToken)
await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
})
it('Should success with the correct parameters', async function () {
await makeGetRequest({ url: server.url, path: path + playlistUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
})
})
@ -177,6 +176,7 @@ describe('Test video playlists API validator', function () {
token: server.accessToken,
playlistAttrs: {
displayName: 'super playlist',
videoChannelId: server.videoChannel.id,
privacy: VideoPlaylistPrivacy.UNLISTED
}
})
@ -187,7 +187,7 @@ describe('Test video playlists API validator', function () {
})
it('Should succeed with the correct params', async function () {
await getVideoPlaylist(server.url, playlistUUID, HttpStatusCode.OK_200)
await getVideoPlaylist(server.url, playlist.uuid, HttpStatusCode.OK_200)
})
})
@ -213,7 +213,7 @@ describe('Test video playlists API validator', function () {
const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail without displayName', async function () {
@ -226,42 +226,42 @@ describe('Test video playlists API validator', function () {
const params = getBase({ displayName: 's'.repeat(300) })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail with an incorrect description', async function () {
const params = getBase({ description: 't' })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail with an incorrect privacy', async function () {
const params = getBase({ privacy: 45 })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail with an unknown video channel id', async function () {
const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail with an incorrect thumbnail file', async function () {
const params = getBase({ thumbnailfile: 'video_short.mp4' })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail with a thumbnail file too big', async function () {
const params = getBase({ thumbnailfile: 'preview-big.png' })
await createVideoPlaylist(params)
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
})
it('Should fail to set "public" a playlist not assigned to a channel', async function () {
@ -272,8 +272,8 @@ describe('Test video playlists API validator', function () {
await createVideoPlaylist(params)
await createVideoPlaylist(params2)
await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID))
await updateVideoPlaylist(getUpdate(params2, playlistUUID))
await updateVideoPlaylist(getUpdate(params3, playlistUUID))
await updateVideoPlaylist(getUpdate(params2, playlist.shortUUID))
await updateVideoPlaylist(getUpdate(params3, playlist.shortUUID))
})
it('Should fail with an unknown playlist to update', async function () {
@ -286,7 +286,7 @@ describe('Test video playlists API validator', function () {
it('Should fail to update a playlist of another user', async function () {
await updateVideoPlaylist(getUpdate(
getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
playlistUUID
playlist.shortUUID
))
})
@ -305,7 +305,7 @@ describe('Test video playlists API validator', function () {
{
const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
await updateVideoPlaylist(getUpdate(params, playlistUUID))
await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
}
})
})
@ -316,7 +316,7 @@ describe('Test video playlists API validator', function () {
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
url: server.url,
token: server.accessToken,
playlistId: playlistUUID,
playlistId: playlist.id,
elementAttrs: Object.assign({
videoId,
startTimestamp: 2,
@ -381,7 +381,7 @@ describe('Test video playlists API validator', function () {
stopTimestamp: 2
}, elementAttrs),
playlistElementId,
playlistId: playlistUUID,
playlistId: playlist.id,
expectedStatus: HttpStatusCode.BAD_REQUEST_400
}, wrapper)
}
@ -451,7 +451,7 @@ describe('Test video playlists API validator', function () {
return Object.assign({
url: server.url,
token: server.accessToken,
playlistId: playlistUUID,
playlistId: playlist.shortUUID,
elementAttrs: Object.assign({
startPosition: 1,
insertAfterPosition: 2,
@ -469,7 +469,7 @@ describe('Test video playlists API validator', function () {
await addVideoInPlaylist({
url: server.url,
token: server.accessToken,
playlistId: playlistUUID,
playlistId: playlist.shortUUID,
elementAttrs: { videoId: id }
})
}
@ -606,7 +606,7 @@ describe('Test video playlists API validator', function () {
url: server.url,
token: server.accessToken,
playlistElementId,
playlistId: playlistUUID,
playlistId: playlist.uuid,
expectedStatus: HttpStatusCode.BAD_REQUEST_400
}, wrapper)
}
@ -662,7 +662,7 @@ describe('Test video playlists API validator', function () {
})
it('Should fail with a playlist of another user', async function () {
await deleteVideoPlaylist(server.url, userAccessToken, playlistUUID, HttpStatusCode.FORBIDDEN_403)
await deleteVideoPlaylist(server.url, userAccessToken, playlist.uuid, HttpStatusCode.FORBIDDEN_403)
})
it('Should fail with the watch later playlist', async function () {
@ -670,7 +670,7 @@ describe('Test video playlists API validator', function () {
})
it('Should succeed with the correct params', async function () {
await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID)
await deleteVideoPlaylist(server.url, server.accessToken, playlist.uuid)
})
})

View File

@ -5,7 +5,7 @@ import * as chai from 'chai'
import { omit } from 'lodash'
import { join } from 'path'
import { randomInt } from '@shared/core-utils'
import { PeerTubeProblemDocument } from '@shared/models'
import { PeerTubeProblemDocument, VideoCreateResult } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import {
checkUploadVideoParam,
@ -42,7 +42,7 @@ describe('Test videos API validator', function () {
let accountName: string
let channelId: number
let channelName: string
let videoId
let video: VideoCreateResult
// ---------------------------------------------------------------
@ -490,7 +490,7 @@ describe('Test videos API validator', function () {
before(async function () {
const res = await getVideosList(server.url)
videoId = res.body.data[0].uuid
video = res.body.data[0]
})
it('Should fail with nothing', async function () {
@ -518,79 +518,79 @@ describe('Test videos API validator', function () {
it('Should fail with a long name', async function () {
const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad category', async function () {
const fields = immutableAssign(baseCorrectParams, { category: 125 })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad licence', async function () {
const fields = immutableAssign(baseCorrectParams, { licence: 125 })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad language', async function () {
const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a long description', async function () {
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a long support text', async function () {
const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad channel', async function () {
const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with too many tags', async function () {
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a tag length too low', async function () {
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a tag length too big', async function () {
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad schedule update (miss updateAt)', async function () {
const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad schedule update (wrong updateAt)', async function () {
const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with a bad originally published at param', async function () {
const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' })
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
})
it('Should fail with an incorrect thumbnail file', async function () {
@ -602,7 +602,7 @@ describe('Test videos API validator', function () {
await makeUploadRequest({
url: server.url,
method: 'PUT',
path: path + videoId,
path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
@ -618,7 +618,7 @@ describe('Test videos API validator', function () {
await makeUploadRequest({
url: server.url,
method: 'PUT',
path: path + videoId,
path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
@ -634,7 +634,7 @@ describe('Test videos API validator', function () {
await makeUploadRequest({
url: server.url,
method: 'PUT',
path: path + videoId,
path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
@ -650,7 +650,7 @@ describe('Test videos API validator', function () {
await makeUploadRequest({
url: server.url,
method: 'PUT',
path: path + videoId,
path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
@ -662,7 +662,7 @@ describe('Test videos API validator', function () {
await makePutBodyRequest({
url: server.url,
path: path + videoId,
path: path + video.shortUUID,
token: userAccessToken,
fields,
statusCodeExpected: HttpStatusCode.FORBIDDEN_403
@ -674,7 +674,7 @@ describe('Test videos API validator', function () {
it('Shoud report the appropriate error', async function () {
const fields = immutableAssign(baseCorrectParams, { licence: 125 })
const res = await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
const res = await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
const error = res.body as PeerTubeProblemDocument
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo')
@ -694,7 +694,7 @@ describe('Test videos API validator', function () {
await makePutBodyRequest({
url: server.url,
path: path + videoId,
path: path + video.shortUUID,
token: server.accessToken,
fields,
statusCodeExpected: HttpStatusCode.NO_CONTENT_204
@ -739,7 +739,7 @@ describe('Test videos API validator', function () {
})
it('Should succeed with the correct parameters', async function () {
await getVideo(server.url, videoId)
await getVideo(server.url, video.shortUUID)
})
})
@ -810,7 +810,7 @@ describe('Test videos API validator', function () {
})
it('Should fail with a video of another user without the appropriate right', async function () {
await removeVideo(server.url, userAccessToken, videoId, HttpStatusCode.FORBIDDEN_403)
await removeVideo(server.url, userAccessToken, video.uuid, HttpStatusCode.FORBIDDEN_403)
})
it('Should fail with a video of another server')
@ -832,7 +832,7 @@ describe('Test videos API validator', function () {
})
it('Should succeed with the correct parameters', async function () {
await removeVideo(server.url, server.accessToken, videoId)
await removeVideo(server.url, server.accessToken, video.uuid)
})
})

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { v4 as uuidv4 } from 'uuid'
import { buildUUID } from '@server/helpers/uuid'
import { AbuseState } from '@shared/models'
import {
addAbuseMessage,
@ -85,7 +85,7 @@ describe('Test moderation notifications', function () {
it('Should send a notification to moderators on local video abuse', async function () {
this.timeout(20000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
@ -98,7 +98,7 @@ describe('Test moderation notifications', function () {
it('Should send a notification to moderators on remote video abuse', async function () {
this.timeout(20000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
@ -114,10 +114,10 @@ describe('Test moderation notifications', function () {
it('Should send a notification to moderators on local comment abuse', async function () {
this.timeout(20000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4())
const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
const comment = resComment.body.comment
await waitJobs(servers)
@ -131,10 +131,10 @@ describe('Test moderation notifications', function () {
it('Should send a notification to moderators on remote comment abuse', async function () {
this.timeout(20000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4())
await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
await waitJobs(servers)
@ -188,7 +188,7 @@ describe('Test moderation notifications', function () {
token: userAccessToken
}
const name = 'abuse ' + uuidv4()
const name = 'abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
@ -236,7 +236,7 @@ describe('Test moderation notifications', function () {
token: servers[0].accessToken
}
const name = 'abuse ' + uuidv4()
const name = 'abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
@ -307,7 +307,7 @@ describe('Test moderation notifications', function () {
it('Should send a notification to video owner on blacklist', async function () {
this.timeout(10000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const uuid = resVideo.body.video.uuid
@ -320,7 +320,7 @@ describe('Test moderation notifications', function () {
it('Should send a notification to video owner on unblacklist', async function () {
this.timeout(10000)
const name = 'video for abuse ' + uuidv4()
const name = 'video for abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const uuid = resVideo.body.video.uuid
@ -507,7 +507,7 @@ describe('Test moderation notifications', function () {
it('Should send notification to moderators on new video with auto-blacklist', async function () {
this.timeout(40000)
videoName = 'video with auto-blacklist ' + uuidv4()
videoName = 'video with auto-blacklist ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName })
videoUUID = resVideo.body.video.uuid
@ -553,7 +553,7 @@ describe('Test moderation notifications', function () {
const updateAt = new Date(new Date().getTime() + 1000000)
const name = 'video with auto-blacklist and future schedule ' + uuidv4()
const name = 'video with auto-blacklist and future schedule ' + buildUUID()
const data = {
name,
@ -586,7 +586,7 @@ describe('Test moderation notifications', function () {
// In 2 seconds
const updateAt = new Date(new Date().getTime() + 2000)
const name = 'video with schedule done and still auto-blacklisted ' + uuidv4()
const name = 'video with schedule done and still auto-blacklisted ' + buildUUID()
const data = {
name,
@ -609,7 +609,7 @@ describe('Test moderation notifications', function () {
it('Should not send a notification to moderators on new video without auto-blacklist', async function () {
this.timeout(60000)
const name = 'video without auto-blacklist ' + uuidv4()
const name = 'video without auto-blacklist ' + buildUUID()
// admin with blacklist right will not be auto-blacklisted
const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name })

View File

@ -2,7 +2,7 @@
import 'mocha'
import * as chai from 'chai'
import { v4 as uuidv4 } from 'uuid'
import { buildUUID } from '@server/helpers/uuid'
import {
cleanupTests,
updateMyUser,
@ -207,7 +207,7 @@ describe('Test user notifications', function () {
it('Should send a new video notification after a video import', async function () {
this.timeout(100000)
const name = 'video import ' + uuidv4()
const name = 'video import ' + buildUUID()
const attributes = {
name,
@ -278,7 +278,7 @@ describe('Test user notifications', function () {
it('Should send a notification when an imported video is transcoded', async function () {
this.timeout(50000)
const name = 'video import ' + uuidv4()
const name = 'video import ' + buildUUID()
const attributes = {
name,
@ -347,7 +347,7 @@ describe('Test user notifications', function () {
it('Should send a notification when the video import failed', async function () {
this.timeout(70000)
const name = 'video import ' + uuidv4()
const name = 'video import ' + buildUUID()
const attributes = {
name,
@ -365,7 +365,7 @@ describe('Test user notifications', function () {
it('Should send a notification when the video import succeeded', async function () {
this.timeout(70000)
const name = 'video import ' + uuidv4()
const name = 'video import ' + buildUUID()
const attributes = {
name,

View File

@ -47,7 +47,7 @@ describe('Test handle downs', function () {
let missedVideo2: Video
let unlistedVideo: Video
const videoIdsServer1: number[] = []
const videoIdsServer1: string[] = []
const videoAttributes = {
name: 'my super name for server 1',

View File

@ -56,7 +56,7 @@ import {
removeServerFromServerBlocklist
} from '../../../../shared/extra-utils/users/blocklist'
import { User } from '../../../../shared/models/users'
import { VideoPrivacy } from '../../../../shared/models/videos'
import { VideoPlaylistCreateResult, VideoPrivacy } from '../../../../shared/models/videos'
import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
@ -427,31 +427,45 @@ describe('Test video playlists', function () {
expect(data).to.have.lengthOf(0)
}
})
})
it('Should not list unlisted or private playlists', async function () {
describe('Playlist rights', function () {
let unlistedPlaylist: VideoPlaylistCreateResult
let privatePlaylist: VideoPlaylistCreateResult
before(async function () {
this.timeout(30000)
await createVideoPlaylist({
url: servers[1].url,
token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist unlisted',
privacy: VideoPlaylistPrivacy.UNLISTED
}
})
{
const res = await createVideoPlaylist({
url: servers[1].url,
token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist unlisted',
privacy: VideoPlaylistPrivacy.UNLISTED,
videoChannelId: servers[1].videoChannel.id
}
})
unlistedPlaylist = res.body.videoPlaylist
}
await createVideoPlaylist({
url: servers[1].url,
token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist private',
privacy: VideoPlaylistPrivacy.PRIVATE
}
})
{
const res = await createVideoPlaylist({
url: servers[1].url,
token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist private',
privacy: VideoPlaylistPrivacy.PRIVATE
}
})
privatePlaylist = res.body.videoPlaylist
}
await waitJobs(servers)
await wait(3000)
})
it('Should not list unlisted or private playlists', async function () {
for (const server of servers) {
const results = [
await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
@ -469,6 +483,27 @@ describe('Test video playlists', function () {
}
}
})
it('Should not get unlisted playlist using only the id', async function () {
await getVideoPlaylist(servers[1].url, unlistedPlaylist.id, 404)
})
it('Should get unlisted plyaylist using uuid or shortUUID', async function () {
await getVideoPlaylist(servers[1].url, unlistedPlaylist.uuid)
await getVideoPlaylist(servers[1].url, unlistedPlaylist.shortUUID)
})
it('Should not get private playlist without token', async function () {
for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
await getVideoPlaylist(servers[1].url, id, 401)
}
})
it('Should get private playlist with a token', async function () {
for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
await getVideoPlaylistWithToken(servers[1].url, servers[1].accessToken, id)
}
})
})
describe('Update playlists', function () {

View File

@ -1,8 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
import * as chai from 'chai'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { Video, VideoCreateResult } from '@shared/models'
import {
cleanupTests,
flushAndRunServer,
@ -13,12 +14,11 @@ import {
uploadVideo
} from '../../../../shared/extra-utils/index'
import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { userLogin } from '../../../../shared/extra-utils/users/login'
import { createUser } from '../../../../shared/extra-utils/users/users'
import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/extra-utils/videos/videos'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { Video } from '@shared/models'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
const expect = chai.expect
@ -32,7 +32,7 @@ describe('Test video privacy', function () {
let internalVideoId: number
let internalVideoUUID: string
let unlistedVideoUUID: string
let unlistedVideo: VideoCreateResult
let nonFederatedUnlistedVideoUUID: string
let now: number
@ -59,231 +59,246 @@ describe('Test video privacy', function () {
await doubleFollow(servers[0], servers[1])
})
it('Should upload a private and internal videos on server 1', async function () {
this.timeout(10000)
describe('Private and internal videos', function () {
for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) {
const attributes = { privacy }
await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
}
it('Should upload a private and internal videos on server 1', async function () {
this.timeout(10000)
await waitJobs(servers)
})
for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) {
const attributes = { privacy }
await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
}
it('Should not have these private and internal videos on server 2', async function () {
const res = await getVideosList(servers[1].url)
await waitJobs(servers)
})
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should not list the private and internal videos for an unauthenticated user on server 1', async function () {
const res = await getVideosList(servers[0].url)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should not list the private video and list the internal video for an authenticated user on server 1', async function () {
const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
expect(res.body.data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL)
})
it('Should list my (private and internal) videos', async function () {
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 10)
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(2)
const videos: Video[] = res.body.data
const privateVideo = videos.find(v => v.privacy.id === VideoPrivacy.PRIVATE)
privateVideoId = privateVideo.id
privateVideoUUID = privateVideo.uuid
const internalVideo = videos.find(v => v.privacy.id === VideoPrivacy.INTERNAL)
internalVideoId = internalVideo.id
internalVideoUUID = internalVideo.uuid
})
it('Should not be able to watch the private/internal video with non authenticated user', async function () {
await getVideo(servers[0].url, privateVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
await getVideo(servers[0].url, internalVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should not be able to watch the private video with another user', async function () {
this.timeout(10000)
const user = {
username: 'hello',
password: 'super password'
}
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
anotherUserToken = await userLogin(servers[0], user)
await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, HttpStatusCode.FORBIDDEN_403)
})
it('Should be able to watch the internal video with another user', async function () {
await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, HttpStatusCode.OK_200)
})
it('Should be able to watch the private video with the correct user', async function () {
await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, HttpStatusCode.OK_200)
})
it('Should upload an unlisted video on server 2', async function () {
this.timeout(60000)
const attributes = {
name: 'unlisted video',
privacy: VideoPrivacy.UNLISTED
}
await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
// Server 2 has transcoding enabled
await waitJobs(servers)
})
it('Should not have this unlisted video listed on server 1 and 2', async function () {
for (const server of servers) {
const res = await getVideosList(server.url)
it('Should not have these private and internal videos on server 2', async function () {
const res = await getVideosList(servers[1].url)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
}
})
})
it('Should list my (unlisted) videos', async function () {
const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1)
it('Should not list the private and internal videos for an unauthenticated user on server 1', async function () {
const res = await getVideosList(servers[0].url)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
unlistedVideoUUID = res.body.data[0].uuid
})
it('Should not list the private video and list the internal video for an authenticated user on server 1', async function () {
const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
it('Should be able to get this unlisted video', async function () {
for (const server of servers) {
const res = await getVideo(server.url, unlistedVideoUUID)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
expect(res.body.name).to.equal('unlisted video')
}
})
expect(res.body.data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL)
})
it('Should upload a non-federating unlisted video to server 1', async function () {
this.timeout(30000)
it('Should list my (private and internal) videos', async function () {
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 10)
const attributes = {
name: 'unlisted video',
privacy: VideoPrivacy.UNLISTED
}
await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
await waitJobs(servers)
})
it('Should list my new unlisted video', async function () {
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3)
expect(res.body.total).to.equal(3)
expect(res.body.data).to.have.lengthOf(3)
nonFederatedUnlistedVideoUUID = res.body.data[0].uuid
})
it('Should be able to get non-federated unlisted video from origin', async function () {
const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID)
expect(res.body.name).to.equal('unlisted video')
})
it('Should not be able to get non-federated unlisted video from federated server', async function () {
await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, HttpStatusCode.NOT_FOUND_404)
})
it('Should update the private and internal videos to public on server 1', async function () {
this.timeout(10000)
now = Date.now()
{
const attribute = {
name: 'private video becomes public',
privacy: VideoPrivacy.PUBLIC
}
await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
}
{
const attribute = {
name: 'internal video becomes public',
privacy: VideoPrivacy.PUBLIC
}
await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
}
await waitJobs(servers)
})
it('Should have this new public video listed on server 1 and 2', async function () {
for (const server of servers) {
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(2)
const videos: Video[] = res.body.data
const privateVideo = videos.find(v => v.name === 'private video becomes public')
const internalVideo = videos.find(v => v.name === 'internal video becomes public')
expect(privateVideo).to.not.be.undefined
expect(internalVideo).to.not.be.undefined
const privateVideo = videos.find(v => v.privacy.id === VideoPrivacy.PRIVATE)
privateVideoId = privateVideo.id
privateVideoUUID = privateVideo.uuid
expect(new Date(privateVideo.publishedAt).getTime()).to.be.at.least(now)
// We don't change the publish date of internal videos
expect(new Date(internalVideo.publishedAt).getTime()).to.be.below(now)
const internalVideo = videos.find(v => v.privacy.id === VideoPrivacy.INTERNAL)
internalVideoId = internalVideo.id
internalVideoUUID = internalVideo.uuid
})
expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
}
it('Should not be able to watch the private/internal video with non authenticated user', async function () {
await getVideo(servers[0].url, privateVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
await getVideo(servers[0].url, internalVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
})
it('Should not be able to watch the private video with another user', async function () {
this.timeout(10000)
const user = {
username: 'hello',
password: 'super password'
}
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
anotherUserToken = await userLogin(servers[0], user)
await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, HttpStatusCode.FORBIDDEN_403)
})
it('Should be able to watch the internal video with another user', async function () {
await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, HttpStatusCode.OK_200)
})
it('Should be able to watch the private video with the correct user', async function () {
await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, HttpStatusCode.OK_200)
})
})
it('Should set these videos as private and internal', async function () {
this.timeout(10000)
describe('Unlisted videos', function () {
await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, { privacy: VideoPrivacy.PRIVATE })
await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.INTERNAL })
it('Should upload an unlisted video on server 2', async function () {
this.timeout(60000)
await waitJobs(servers)
const attributes = {
name: 'unlisted video',
privacy: VideoPrivacy.UNLISTED
}
await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
for (const server of servers) {
const res = await getVideosList(server.url)
// Server 2 has transcoding enabled
await waitJobs(servers)
})
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
}
it('Should not have this unlisted video listed on server 1 and 2', async function () {
for (const server of servers) {
const res = await getVideosList(server.url)
{
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
const videos = res.body.data
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
}
})
it('Should list my (unlisted) videos', async function () {
const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
unlistedVideo = res.body.data[0]
})
it('Should not be able to get this unlisted video using its id', async function () {
await getVideo(servers[1].url, unlistedVideo.id, 404)
})
it('Should be able to get this unlisted video using its uuid/shortUUID', async function () {
for (const server of servers) {
for (const id of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) {
const res = await getVideo(server.url, id)
expect(res.body.name).to.equal('unlisted video')
}
}
})
it('Should upload a non-federating unlisted video to server 1', async function () {
this.timeout(30000)
const attributes = {
name: 'unlisted video',
privacy: VideoPrivacy.UNLISTED
}
await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
await waitJobs(servers)
})
it('Should list my new unlisted video', async function () {
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3)
expect(res.body.total).to.equal(3)
expect(videos).to.have.lengthOf(3)
expect(res.body.data).to.have.lengthOf(3)
const privateVideo = videos.find(v => v.name === 'private video becomes public')
const internalVideo = videos.find(v => v.name === 'internal video becomes public')
nonFederatedUnlistedVideoUUID = res.body.data[0].uuid
})
expect(privateVideo).to.not.be.undefined
expect(internalVideo).to.not.be.undefined
it('Should be able to get non-federated unlisted video from origin', async function () {
const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID)
expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL)
expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE)
}
expect(res.body.name).to.equal('unlisted video')
})
it('Should not be able to get non-federated unlisted video from federated server', async function () {
await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, HttpStatusCode.NOT_FOUND_404)
})
})
describe('Privacy update', function () {
it('Should update the private and internal videos to public on server 1', async function () {
this.timeout(10000)
now = Date.now()
{
const attribute = {
name: 'private video becomes public',
privacy: VideoPrivacy.PUBLIC
}
await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
}
{
const attribute = {
name: 'internal video becomes public',
privacy: VideoPrivacy.PUBLIC
}
await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
}
await waitJobs(servers)
})
it('Should have this new public video listed on server 1 and 2', async function () {
for (const server of servers) {
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(2)
const videos: Video[] = res.body.data
const privateVideo = videos.find(v => v.name === 'private video becomes public')
const internalVideo = videos.find(v => v.name === 'internal video becomes public')
expect(privateVideo).to.not.be.undefined
expect(internalVideo).to.not.be.undefined
expect(new Date(privateVideo.publishedAt).getTime()).to.be.at.least(now)
// We don't change the publish date of internal videos
expect(new Date(internalVideo.publishedAt).getTime()).to.be.below(now)
expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
}
})
it('Should set these videos as private and internal', async function () {
this.timeout(10000)
await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, { privacy: VideoPrivacy.PRIVATE })
await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.INTERNAL })
await waitJobs(servers)
for (const server of servers) {
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
}
{
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
const videos = res.body.data
expect(res.body.total).to.equal(3)
expect(videos).to.have.lengthOf(3)
const privateVideo = videos.find(v => v.name === 'private video becomes public')
const internalVideo = videos.find(v => v.name === 'internal video becomes public')
expect(privateVideo).to.not.be.undefined
expect(internalVideo).to.not.be.undefined
expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL)
expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE)
}
})
})
after(async function () {

View File

@ -2,7 +2,10 @@
import 'mocha'
import * as chai from 'chai'
import { waitJobs } from '../../../shared/extra-utils/server/jobs'
import { createFile, readdir } from 'fs-extra'
import { join } from 'path'
import { buildUUID } from '@server/helpers/uuid'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import {
buildServerDirectory,
cleanupTests,
@ -21,11 +24,8 @@ import {
uploadVideo,
wait
} from '../../../shared/extra-utils'
import { waitJobs } from '../../../shared/extra-utils/server/jobs'
import { Account, VideoPlaylistPrivacy } from '../../../shared/models'
import { createFile, readdir } from 'fs-extra'
import { v4 as uuidv4 } from 'uuid'
import { join } from 'path'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
const expect = chai.expect
@ -131,8 +131,8 @@ describe('Test prune storage scripts', function () {
{
const base = buildServerDirectory(servers[0], 'videos')
const n1 = uuidv4() + '.mp4'
const n2 = uuidv4() + '.webm'
const n1 = buildUUID() + '.mp4'
const n2 = buildUUID() + '.webm'
await createFile(join(base, n1))
await createFile(join(base, n2))
@ -143,8 +143,8 @@ describe('Test prune storage scripts', function () {
{
const base = buildServerDirectory(servers[0], 'torrents')
const n1 = uuidv4() + '-240.torrent'
const n2 = uuidv4() + '-480.torrent'
const n1 = buildUUID() + '-240.torrent'
const n2 = buildUUID() + '-480.torrent'
await createFile(join(base, n1))
await createFile(join(base, n2))
@ -155,8 +155,8 @@ describe('Test prune storage scripts', function () {
{
const base = buildServerDirectory(servers[0], 'thumbnails')
const n1 = uuidv4() + '.jpg'
const n2 = uuidv4() + '.jpg'
const n1 = buildUUID() + '.jpg'
const n2 = buildUUID() + '.jpg'
await createFile(join(base, n1))
await createFile(join(base, n2))
@ -167,8 +167,8 @@ describe('Test prune storage scripts', function () {
{
const base = buildServerDirectory(servers[0], 'previews')
const n1 = uuidv4() + '.jpg'
const n2 = uuidv4() + '.jpg'
const n1 = buildUUID() + '.jpg'
const n2 = buildUUID() + '.jpg'
await createFile(join(base, n1))
await createFile(join(base, n2))
@ -179,8 +179,8 @@ describe('Test prune storage scripts', function () {
{
const base = buildServerDirectory(servers[0], 'avatars')
const n1 = uuidv4() + '.png'
const n2 = uuidv4() + '.jpg'
const n1 = buildUUID() + '.png'
const n2 = buildUUID() + '.jpg'
await createFile(join(base, n1))
await createFile(join(base, n2))

View File

@ -3,9 +3,8 @@
import 'mocha'
import * as chai from 'chai'
import { omit } from 'lodash'
import * as request from 'supertest'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { Account, CustomConfig, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models'
import { Account, CustomConfig, HTMLServerConfig, ServerConfig, VideoPlaylistCreateResult, VideoPlaylistPrivacy } from '@shared/models'
import {
addVideoInPlaylist,
cleanupTests,
@ -50,13 +49,16 @@ describe('Test a client controllers', function () {
const playlistName = 'super playlist name'
const playlistDescription = 'super playlist description'
let playlistUUID: string
let playlist: VideoPlaylistCreateResult
const channelDescription = 'my super channel description'
const watchVideoBasePaths = [ '/videos/watch/', '/w/' ]
const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ]
let videoIds: (string | number)[] = []
let playlistIds: (string | number)[] = []
before(async function () {
this.timeout(120000)
@ -79,7 +81,9 @@ describe('Test a client controllers', function () {
const videos = resVideosRequest.body.data
expect(videos.length).to.equal(1)
servers[0].video = videos[0]
const video = videos[0]
servers[0].video = video
videoIds = [ video.id, video.uuid, video.shortUUID ]
// Playlist
@ -91,16 +95,14 @@ describe('Test a client controllers', function () {
}
const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
const playlist = resVideoPlaylistRequest.body.videoPlaylist
const playlistId = playlist.id
playlistUUID = playlist.uuid
playlist = resVideoPlaylistRequest.body.videoPlaylist
playlistIds = [ playlist.id, playlist.shortUUID, playlist.uuid ]
await addVideoInPlaylist({
url: servers[0].url,
token: servers[0].accessToken,
playlistId,
elementAttrs: { videoId: servers[0].video.id }
playlistId: playlist.shortUUID,
elementAttrs: { videoId: video.id }
})
// Account
@ -117,36 +119,43 @@ describe('Test a client controllers', function () {
it('Should have valid oEmbed discovery tags for videos', async function () {
for (const basePath of watchVideoBasePaths) {
const path = basePath + servers[0].video.uuid
const res = await request(servers[0].url)
.get(path)
.set('Accept', 'text/html')
.expect(HttpStatusCode.OK_200)
for (const id of videoIds) {
const res = await makeGetRequest({
url: servers[0].url,
path: basePath + id,
accept: 'text/html',
statusCodeExpected: HttpStatusCode.OK_200
})
const port = servers[0].port
const port = servers[0].port
const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
`url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2F${servers[0].video.uuid}" ` +
`title="${servers[0].video.name}" />`
const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
`url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2F${servers[0].video.uuid}" ` +
`title="${servers[0].video.name}" />`
expect(res.text).to.contain(expectedLink)
expect(res.text).to.contain(expectedLink)
}
}
})
it('Should have valid oEmbed discovery tags for a playlist', async function () {
for (const basePath of watchPlaylistBasePaths) {
const res = await request(servers[0].url)
.get(basePath + playlistUUID)
.set('Accept', 'text/html')
.expect(HttpStatusCode.OK_200)
for (const id of playlistIds) {
const res = await makeGetRequest({
url: servers[0].url,
path: basePath + id,
accept: 'text/html',
statusCodeExpected: HttpStatusCode.OK_200
})
const port = servers[0].port
const port = servers[0].port
const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
`url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlistUUID}" ` +
`title="${playlistName}" />`
const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
`url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlist.uuid}" ` +
`title="${playlistName}" />`
expect(res.text).to.contain(expectedLink)
expect(res.text).to.contain(expectedLink)
}
}
})
})
@ -190,7 +199,7 @@ describe('Test a client controllers', function () {
expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
expect(text).to.contain('<meta property="og:type" content="video" />')
expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlistUUID}" />`)
expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlist.uuid}" />`)
}
it('Should have valid Open Graph tags on the account page', async function () {
@ -206,15 +215,19 @@ describe('Test a client controllers', function () {
})
it('Should have valid Open Graph tags on the watch page', async function () {
await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.id)
for (const path of watchVideoBasePaths) {
for (const id of videoIds) {
await watchVideoPageTest(path + id)
}
}
})
it('Should have valid Open Graph tags on the watch playlist page', async function () {
await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
await watchPlaylistPageTest('/w/p/' + playlistUUID)
for (const path of watchPlaylistBasePaths) {
for (const id of playlistIds) {
await watchPlaylistPageTest(path + id)
}
}
})
})
@ -263,15 +276,19 @@ describe('Test a client controllers', function () {
}
it('Should have valid twitter card on the watch video page', async function () {
await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.id)
for (const path of watchVideoBasePaths) {
for (const id of videoIds) {
await watchVideoPageTest(path + id)
}
}
})
it('Should have valid twitter card on the watch playlist page', async function () {
await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
await watchPlaylistPageTest('/w/p/' + playlistUUID)
for (const path of watchPlaylistBasePaths) {
for (const id of playlistIds) {
await watchPlaylistPageTest(path + id)
}
}
})
it('Should have valid twitter card on the account page', async function () {
@ -333,15 +350,19 @@ describe('Test a client controllers', function () {
}
it('Should have valid twitter card on the watch video page', async function () {
await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.uuid)
await watchVideoPageTest('/w/' + servers[0].video.id)
for (const path of watchVideoBasePaths) {
for (const id of videoIds) {
await watchVideoPageTest(path + id)
}
}
})
it('Should have valid twitter card on the watch playlist page', async function () {
await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
await watchPlaylistPageTest('/w/p/' + playlistUUID)
for (const path of watchPlaylistBasePaths) {
for (const id of playlistIds) {
await watchPlaylistPageTest(path + id)
}
}
})
it('Should have valid twitter card on the account page', async function () {
@ -399,8 +420,10 @@ describe('Test a client controllers', function () {
it('Should use the original video URL for the canonical tag', async function () {
for (const basePath of watchVideoBasePaths) {
const res = await makeHTMLRequest(servers[1].url, basePath + servers[0].video.uuid)
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
for (const id of videoIds) {
const res = await makeHTMLRequest(servers[1].url, basePath + id)
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
}
}
})
@ -426,8 +449,10 @@ describe('Test a client controllers', function () {
it('Should use the original playlist URL for the canonical tag', async function () {
for (const basePath of watchPlaylistBasePaths) {
const res = await makeHTMLRequest(servers[1].url, basePath + playlistUUID)
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`)
for (const id of playlistIds) {
const res = await makeHTMLRequest(servers[1].url, basePath + id)
expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlist.uuid}" />`)
}
}
})
})

View File

@ -4,7 +4,6 @@ registerTSPaths()
import * as repl from 'repl'
import * as path from 'path'
import * as _ from 'lodash'
import { uuidv1, uuidv3, uuidv4, uuidv5 } from 'uuid'
import * as Sequelize from 'sequelize'
import * as YoutubeDL from 'youtube-dl'
import { initDatabaseModels, sequelizeTypescript } from '../initializers/database'
@ -31,10 +30,6 @@ const start = async () => {
env: process.env,
lodash: _,
path,
uuidv1,
uuidv3,
uuidv4,
uuidv5,
cli,
logger,
constants,

View File

@ -43,6 +43,7 @@ interface ServerInfo {
video?: {
id: number
uuid: string
shortUUID: string
name?: string
url?: string

View File

@ -6,9 +6,9 @@ import got, { Response as GotResponse } from 'got/dist/source'
import * as parseTorrent from 'parse-torrent'
import { join } from 'path'
import * as request from 'supertest'
import { v4 as uuidv4 } from 'uuid'
import validator from 'validator'
import { getLowercaseExtension } from '@server/helpers/core-utils'
import { buildUUID } from '@server/helpers/uuid'
import { HttpStatusCode } from '@shared/core-utils'
import { VideosCommonQuery } from '@shared/models'
import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants'
@ -806,7 +806,7 @@ async function uploadVideoAndGetId (options: {
const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
return { id: res.body.video.id, uuid: res.body.video.uuid }
return res.body.video as { id: number, uuid: string, shortUUID: string }
}
async function getLocalIdByUUID (url: string, uuid: string) {
@ -827,7 +827,7 @@ async function uploadRandomVideoOnServers (servers: ServerInfo[], serverNumber:
async function uploadRandomVideo (server: ServerInfo, wait = true, additionalParams: any = {}) {
const prefixName = additionalParams.prefixName || ''
const name = prefixName + uuidv4()
const name = prefixName + buildUUID()
const data = Object.assign({ name }, additionalParams)
const res = await uploadVideo(server.url, server.accessToken, data)

View File

@ -0,0 +1 @@
export * from './result-list.model'

View File

@ -1,16 +1,16 @@
export * from './activitypub'
export * from './actors'
export * from './moderation'
export * from './custom-markup'
export * from './bulk'
export * from './redundancy'
export * from './users'
export * from './videos'
export * from './common'
export * from './custom-markup'
export * from './feeds'
export * from './joinpeertube'
export * from './moderation'
export * from './overviews'
export * from './plugins'
export * from './redundancy'
export * from './search'
export * from './server'
export * from './oauth-client-local.model'
export * from './result-list.model'
export * from './tokens'
export * from './users'
export * from './videos'

View File

@ -10,7 +10,7 @@ export interface AbuseCreate {
}
video?: {
id: number
id: number | string
startAt?: number
endAt?: number
}

View File

@ -0,0 +1 @@
export * from './oauth-client-local.model'

View File

@ -35,3 +35,4 @@ export * from './video-transcoding-fps.model'
export * from './video-update.model'
export * from './video.model'
export * from './video-create-result.model'

View File

@ -1,4 +1,5 @@
export * from './video-exist-in-playlist.model'
export * from './video-playlist-create-result.model'
export * from './video-playlist-create.model'
export * from './video-playlist-element-create.model'
export * from './video-playlist-element-update.model'

View File

@ -0,0 +1,5 @@
export interface VideoPlaylistCreateResult {
id: number
uuid: string
shortUUID: string
}

View File

@ -6,6 +6,8 @@ import { VideoPlaylistType } from './video-playlist-type.model'
export interface VideoPlaylist {
id: number
uuid: string
shortUUID: string
isLocal: boolean
url: string

View File

@ -0,0 +1,5 @@
export interface VideoCreateResult {
id: number
uuid: string
shortUUID: string
}

View File

@ -10,6 +10,8 @@ import { VideoStreamingPlaylist } from './video-streaming-playlist.model'
export interface Video {
id: number
uuid: string
shortUUID: string
createdAt: Date | string
updatedAt: Date | string
publishedAt: Date | string

View File

@ -3003,6 +3003,8 @@ paths:
$ref: '#/components/schemas/VideoPlaylist/properties/id'
uuid:
$ref: '#/components/schemas/VideoPlaylist/properties/uuid'
shortUUID:
$ref: '#/components/schemas/VideoPlaylist/properties/shortUUID'
requestBody:
content:
multipart/form-data:
@ -4543,11 +4545,12 @@ components:
name: id
in: path
required: true
description: The object id or uuid
description: The object id, uuid or short uuid
schema:
oneOf:
- $ref: '#/components/schemas/id'
- $ref: '#/components/schemas/UUIDv4'
- $ref: '#/components/schemas/shortUUID'
playlistId:
name: playlistId
in: path
@ -4812,6 +4815,10 @@ components:
pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
minLength: 36
maxLength: 36
shortUUID:
type: string
description: translation of a uuid v4 with a bigger alphabet to have a shorter uuid
example: 2y84q2MQUMWPbiEcxNXMgC
username:
type: string
description: immutable name of the user, used to find or mention its actor
@ -5141,6 +5148,9 @@ components:
description: universal identifier for the video, that can be used across instances
allOf:
- $ref: '#/components/schemas/UUIDv4'
shortUUID:
allOf:
- $ref: '#/components/schemas/shortUUID'
isLive:
type: boolean
createdAt:
@ -5520,6 +5530,9 @@ components:
$ref: '#/components/schemas/id'
uuid:
$ref: '#/components/schemas/UUIDv4'
shortUUID:
allOf:
- $ref: '#/components/schemas/shortUUID'
createdAt:
type: string
format: date-time
@ -6295,6 +6308,8 @@ components:
$ref: '#/components/schemas/Video/properties/id'
uuid:
$ref: '#/components/schemas/Video/properties/uuid'
shortUUID:
$ref: '#/components/schemas/Video/properties/shortUUID'
CommentThreadResponse:
properties:
total:

View File

@ -7260,6 +7260,14 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
short-uuid@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-4.2.0.tgz#3706d9e7287ac589dc5ffe324d3e34817a07540b"
integrity sha512-r3cxuPPZSuF0QkKsK9bBR7u+7cwuCRzWzgjPh07F5N2iIUNgblnMHepBY16xgj5t1lG9iOP9k/TEafY1qhRzaw==
dependencies:
any-base "^1.1.0"
uuid "^8.3.2"
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"