}
getVideoUrl (videoBlock: VideoBlacklist) {
- return Video.buildClientUrl(videoBlock.video.uuid)
+ return Video.buildWatchUrl(videoBlock.video)
}
toHtml (text: string) {
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({
}
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 () {
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({
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])
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
}
protected buildUrl (playlist: VideoPlaylist) {
- return '/w/p/' + playlist.uuid
+ return VideoPlaylist.buildWatchUrl(playlist)
}
}
}
protected buildUrl (video: Video) {
- return '/w/' + video.uuid
+ return Video.buildWatchUrl(video)
}
}
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'
() => {
this.notifier.success($localize`Live published.`)
- this.router.navigate(['/w', video.uuid])
+ this.router.navigateByUrl(Video.buildWatchUrl(video))
},
err => {
+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',
this.isUploadingVideo = false
this.notifier.success($localize`Video published.`)
- this.router.navigate([ '/w', video.uuid ])
+ this.router.navigateByUrl(Video.buildWatchUrl(video))
},
err => {
<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">
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'
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 => {
pluginData: this.video.pluginData
})
}
+
+ getVideoUrl () {
+ return Video.buildWatchUrl(this.videoDetails)
+ }
}
</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>
<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>
this.componentPagination.totalItems = null
this.totalNotDeletedComments = null
- this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video.uuid)
+ this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video)
this.loadMoreThreads()
}
}
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
}
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()
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(
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)
}
}
}
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) {
templateUrl: './link.component.html'
})
export class LinkComponent {
- @Input() internalLink?: any[]
+ @Input() internalLink?: string | any[]
@Input() href?: string
@Input() target?: string
UserRight,
VideoInfo
} from '@shared/models'
+import { Video } from '../video'
export class UserNotification implements UserNotificationServer {
id: number
}
private buildVideoUrl (video: { uuid: string }) {
- return '/w/' + video.uuid
+ return Video.buildWatchUrl(video)
}
private buildAccountUrl (account: { name: string, host: string }) {
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
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 = {}) {
this.id = hash.id
this.uuid = hash.uuid
+ this.shortUUID = hash.shortUUID
this.isLocal = hash.isLocal
this.name = hash.name
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'
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
@Input() video: Video
@Input() nsfw = false
- @Input() videoRouterLink: any[]
+ @Input() videoRouterLink: string | any[]
@Input() queryParams: { [ p: string ]: any }
@Input() videoHref: string
@Input() videoTarget: string
getVideoRouterLink () {
if (this.videoRouterLink) return this.videoRouterLink
- return [ '/w', this.video.uuid ]
+ return Video.buildWatchUrl(this.video)
}
onWatchLaterClick (event: Event) {
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 {
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
FeedFormat,
ResultList,
ThreadsResultList,
+ Video,
VideoComment as VideoCommentServerModel,
VideoCommentAdmin,
VideoCommentCreate,
)
}
- getVideoCommentsFeeds (videoUUID?: string) {
+ getVideoCommentsFeeds (video: Pick<Video, 'uuid'>) {
const feeds = [
{
format: FeedFormat.RSS,
}
]
- if (videoUUID !== undefined) {
+ if (video !== undefined) {
for (const feed of feeds) {
- feed.url += '?videoId=' + videoUUID
+ feed.url += '?videoId=' + video.uuid
}
}
playlistElementId?: number
}
- videoRouterLink: any[] = []
+ videoRouterLink: string | any[] = []
videoHref: string
videoTarget: string
buildVideoLink () {
if (this.videoLinkType === 'internal' || !this.video.url) {
- this.videoRouterLink = [ '/w', this.video.uuid ]
+ this.videoRouterLink = Video.buildWatchUrl(this.video)
return
}
buildRouterLink () {
if (!this.playlist) return null
- return [ '/w/p', this.playlist.uuid ]
+ return VideoPlaylist.buildWatchUrl(this.playlist)
}
buildRouterQuery () {
}
if (this.linkType === 'internal' || !this.playlist.url) {
- this.routerLink = [ '/w/p', this.playlist.uuid ]
+ this.routerLink = VideoPlaylist.buildWatchUrl(this.playlist)
return
}
export class VideoPlaylist implements ServerVideoPlaylist {
id: number
uuid: string
+ shortUUID: string
+
isLocal: boolean
url: string
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
"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",
"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",
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'
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({
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'
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 })
return res.json({
videoPlaylist: {
id: videoPlaylistCreated.id,
+ shortUUID: uuidToShort(videoPlaylistCreated.uuid),
uuid: videoPlaylistCreated.uuid
}
})
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'
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()
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,
return res.json({
video: {
id: videoCreated.id,
+ shortUUID: uuidToShort(videoCreated.uuid),
uuid: videoCreated.uuid
}
})
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'
return res.json({
video: {
id: videoCreated.id,
+ shortUUID: uuidToShort(videoCreated.uuid),
uuid: videoCreated.uuid
}
})
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
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[],
// ---------------------------------------------------------------------------
+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,
isIdValid,
isSafePath,
isUUIDValid,
+ toCompleteUUID,
isIdOrUUIDValid,
isDateValid,
toValueOrNull,
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 (
--- /dev/null
+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
+}
+import { buildUUID } from '@server/helpers/uuid'
import * as Sequelize from 'sequelize'
-import { v4 as uuidv4 } from 'uuid'
async function up (utils: {
transaction: Sequelize.Transaction
{
const authors = await utils.db.Author.findAll()
for (const author of authors) {
- author.uuid = uuidv4()
+ author.uuid = buildUUID()
await author.save()
}
}
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: {
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 = `
import * as Sequelize from 'sequelize'
-import { v4 as uuidv4 } from 'uuid'
+import { buildUUID } from '@server/helpers/uuid'
async function up (utils: {
transaction: Sequelize.Transaction
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)
}
}
-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'
if (!extension) return undefined
return {
- name: uuidv4() + extension,
+ name: buildUUID() + extension,
fileUrl: icon.url,
height: icon.height,
width: icon.width,
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
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)
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)
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'
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)
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'
// 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`
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'
body('video.id')
.optional()
+ .customSanitizer(toCompleteUUID)
.custom(isIdOrUUIDValid)
.withMessage('Should have a valid videoId'),
body('video.startAt')
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,
]
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 })
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'
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'
})
}
- const elementId = matches[1]
+ const elementId = toCompleteUUID(matches[1])
if (isIdOrUUIDValid(elementId) === false) {
return res.fail({ message: 'Invalid video or playlist id.' })
}
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'),
]
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'),
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) => {
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) {
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
}
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,
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')
]
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 })
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 })
]
const videosBlacklistAddValidator = [
- param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
+ isValidVideoIdParam('videoId'),
+
body('unfederate')
.optional()
.customSanitizer(toBooleanOrNull)
]
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'),
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(
]
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 })
]
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 })
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')
]
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 })
]
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 })
]
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 })
]
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) => {
]
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 })
]
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) => {
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'
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 })
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'
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 })
]
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 })
isIdOrUUIDValid,
isIdValid,
isUUIDValid,
+ toCompleteUUID,
toIntArray,
toIntOrNull,
toValueOrNull
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')
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()
])
const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
- param('playlistId')
- .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
+ isValidPlaylistIdParam('playlistId'),
body('displayName')
.optional()
])
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 })
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 })
]
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()
]
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()
]
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'),
]
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')
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) => {
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 })
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'),
isBooleanValid,
isDateValid,
isFileFieldValid,
- isIdOrUUIDValid,
isIdValid,
isUUIDValid,
toArray,
checkUserCanManageVideo,
doesVideoChannelOfAccountExist,
doesVideoExist,
- doesVideoFileOfVideoExist
+ doesVideoFileOfVideoExist,
+ isValidVideoIdParam
} from '../shared'
const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
])
const videosUpdateValidator = getCommonVideoEditAttributes().concat([
- param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
+ isValidVideoIdParam('id'),
+
body('name')
.optional()
.trim()
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 })
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 })
])
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 })
+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'
const videoObject: Video = {
id: video.id,
uuid: video.uuid,
+ shortUUID: uuidToShort(video.uuid),
+
name: video.name,
category: {
id: video.category,
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'
}
static generateCaptionName (language: string) {
- return `${uuidv4()}-${language}.vtt`
+ return `${buildUUID()}-${language}.vtt`
}
isOwned () {
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'
generateThumbnailName () {
const extension = '.jpg'
- return 'playlist-' + uuidv4() + extension
+ return 'playlist-' + buildUUID() + extension
}
getThumbnailUrl () {
return {
id: this.id,
uuid: this.uuid,
+ shortUUID: uuidToShort(this.uuid),
+
isLocal: this.isOwned(),
url: this.url,
/* 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)
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 () {
})
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,
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,
let server: ServerInfo
let userAccessToken = ''
let channelId: number
- let videoId: number
+ let video: VideoCreateResult
let videoIdNotLive: number
// ---------------------------------------------------------------
statusCodeExpected: HttpStatusCode.OK_200
})
- videoId = res.body.video.id
+ video = res.body.video
})
it('Should forbid if live is disabled', async 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 () {
})
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 () {
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 () {
}
})
- 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)
})
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)
})
/* 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,
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
// ---------------------------------------------------------------
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 () {
})
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 () {
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
+ })
})
})
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,
let userId: number
let rootId: number
let moderatorId: number
- let videoId: number
+ let video: VideoCreateResult
let server: ServerInfo
let serverWithRegistrationDisabled: ServerInfo
let userAccessToken = ''
{
const res = await uploadVideo(server.url, server.accessToken, {})
- videoId = res.body.video.id
+ video = res.body.video
}
{
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 () {
})
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)
})
})
})
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({
})
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
+ }
})
})
/* 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,
let server: ServerInfo
let userAccessToken: string
- let videoUUID: string
+ let video: VideoCreateResult
// ---------------------------------------------------------------
{
const res = await uploadVideo(server.url, server.accessToken, {})
- videoUUID = res.body.video.uuid
+ video = res.body.video
}
{
})
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,
})
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,
})
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,
})
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,
// '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,
// 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
url: server.url,
accessToken: server.accessToken,
language: 'zh',
- videoId: videoUUID,
+ videoId: video.uuid,
fixture: 'subtitle-good.srt',
mimeType: 'application/octet-stream'
})
// '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,
// })
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,
})
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 })
})
})
})
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,
})
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,
/* 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,
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
let pathThread: string
let pathComment: string
let server: ServerInfo
- let videoUUID: string
+ let video: VideoCreateResult
let userAccessToken: string
let userAccessToken2: string
let commentId: number
{
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
}
{
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
})
})
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
})
})
})
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'
}
})
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 })
})
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 })
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 () {
/* 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,
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
videoChannelId: server.videoChannel.id
}
})
- playlistUUID = res.body.videoPlaylist.uuid
+ playlist = res.body.videoPlaylist
}
{
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 })
})
})
token: server.accessToken,
playlistAttrs: {
displayName: 'super playlist',
+ videoChannelId: server.videoChannel.id,
privacy: VideoPlaylistPrivacy.UNLISTED
}
})
})
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)
})
})
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 () {
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 () {
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 () {
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
))
})
{
const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
- await updateVideoPlaylist(getUpdate(params, playlistUUID))
+ await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
}
})
})
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
url: server.url,
token: server.accessToken,
- playlistId: playlistUUID,
+ playlistId: playlist.id,
elementAttrs: Object.assign({
videoId,
startTimestamp: 2,
stopTimestamp: 2
}, elementAttrs),
playlistElementId,
- playlistId: playlistUUID,
+ playlistId: playlist.id,
expectedStatus: HttpStatusCode.BAD_REQUEST_400
}, wrapper)
}
return Object.assign({
url: server.url,
token: server.accessToken,
- playlistId: playlistUUID,
+ playlistId: playlist.shortUUID,
elementAttrs: Object.assign({
startPosition: 1,
insertAfterPosition: 2,
await addVideoInPlaylist({
url: server.url,
token: server.accessToken,
- playlistId: playlistUUID,
+ playlistId: playlist.shortUUID,
elementAttrs: { videoId: id }
})
}
url: server.url,
token: server.accessToken,
playlistElementId,
- playlistId: playlistUUID,
+ playlistId: playlist.uuid,
expectedStatus: HttpStatusCode.BAD_REQUEST_400
}, wrapper)
}
})
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 () {
})
it('Should succeed with the correct params', async function () {
- await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID)
+ await deleteVideoPlaylist(server.url, server.accessToken, playlist.uuid)
})
})
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,
let accountName: string
let channelId: number
let channelName: string
- let videoId
+ let video: VideoCreateResult
// ---------------------------------------------------------------
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 () {
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 () {
await makeUploadRequest({
url: server.url,
method: 'PUT',
- path: path + videoId,
+ path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
await makeUploadRequest({
url: server.url,
method: 'PUT',
- path: path + videoId,
+ path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
await makeUploadRequest({
url: server.url,
method: 'PUT',
- path: path + videoId,
+ path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
await makeUploadRequest({
url: server.url,
method: 'PUT',
- path: path + videoId,
+ path: path + video.shortUUID,
token: server.accessToken,
fields,
attaches
await makePutBodyRequest({
url: server.url,
- path: path + videoId,
+ path: path + video.shortUUID,
token: userAccessToken,
fields,
statusCodeExpected: HttpStatusCode.FORBIDDEN_403
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')
await makePutBodyRequest({
url: server.url,
- path: path + videoId,
+ path: path + video.shortUUID,
token: server.accessToken,
fields,
statusCodeExpected: HttpStatusCode.NO_CONTENT_204
})
it('Should succeed with the correct parameters', async function () {
- await getVideo(server.url, videoId)
+ await getVideo(server.url, video.shortUUID)
})
})
})
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')
})
it('Should succeed with the correct parameters', async function () {
- await removeVideo(server.url, server.accessToken, videoId)
+ await removeVideo(server.url, server.accessToken, video.uuid)
})
})
/* 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,
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
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
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)
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)
token: userAccessToken
}
- const name = 'abuse ' + uuidv4()
+ const name = 'abuse ' + buildUUID()
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
const video = resVideo.body.video
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
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
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
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
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,
// 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,
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 })
import 'mocha'
import * as chai from 'chai'
-import { v4 as uuidv4 } from 'uuid'
+import { buildUUID } from '@server/helpers/uuid'
import {
cleanupTests,
updateMyUser,
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,
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,
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,
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,
let missedVideo2: Video
let unlistedVideo: Video
- const videoIdsServer1: number[] = []
+ const videoIdsServer1: string[] = []
const videoAttributes = {
name: 'my super name for server 1',
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'
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'),
}
}
})
+
+ 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 () {
/* 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,
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
let internalVideoId: number
let internalVideoUUID: string
- let unlistedVideoUUID: string
+ let unlistedVideo: VideoCreateResult
let nonFederatedUnlistedVideoUUID: string
let now: number
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 have these private and internal videos on server 2', async function () {
+ const res = await getVideosList(servers[1].url)
- 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)
+ })
- 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)
+ 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.total).to.equal(1)
+ expect(res.body.data).to.have.lengthOf(1)
- expect(res.body.data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL)
- })
+ 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)
+ 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)
+ expect(res.body.total).to.equal(2)
+ expect(res.body.data).to.have.lengthOf(2)
- const videos: Video[] = res.body.data
+ const videos: Video[] = res.body.data
- const privateVideo = videos.find(v => v.privacy.id === VideoPrivacy.PRIVATE)
- privateVideoId = privateVideo.id
- privateVideoUUID = privateVideo.uuid
+ 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
- })
+ 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/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)
+ 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 })
+ 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)
- })
+ 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 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 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)
+ describe('Unlisted videos', function () {
- const attributes = {
- name: 'unlisted video',
- privacy: VideoPrivacy.UNLISTED
- }
- await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
+ it('Should upload an unlisted video on server 2', async function () {
+ this.timeout(60000)
- // Server 2 has transcoding enabled
- await waitJobs(servers)
- })
+ const attributes = {
+ name: 'unlisted video',
+ privacy: VideoPrivacy.UNLISTED
+ }
+ await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
- 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)
+ // 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)
- 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(0)
+ expect(res.body.data).to.have.lengthOf(0)
+ }
+ })
- expect(res.body.total).to.equal(1)
- expect(res.body.data).to.have.lengthOf(1)
+ it('Should list my (unlisted) videos', async function () {
+ const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1)
- unlistedVideoUUID = res.body.data[0].uuid
- })
+ expect(res.body.total).to.equal(1)
+ expect(res.body.data).to.have.lengthOf(1)
- it('Should be able to get this unlisted video', async function () {
- for (const server of servers) {
- const res = await getVideo(server.url, unlistedVideoUUID)
+ unlistedVideo = res.body.data[0]
+ })
- expect(res.body.name).to.equal('unlisted video')
- }
- })
+ 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 upload a non-federating unlisted video to server 1', async function () {
- this.timeout(30000)
+ 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)
- const attributes = {
- name: 'unlisted video',
- privacy: VideoPrivacy.UNLISTED
- }
- await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
+ expect(res.body.name).to.equal('unlisted video')
+ }
+ }
+ })
- await waitJobs(servers)
- })
+ 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)
- it('Should list my new unlisted video', async function () {
- const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3)
+ await waitJobs(servers)
+ })
- expect(res.body.total).to.equal(3)
- expect(res.body.data).to.have.lengthOf(3)
+ it('Should list my new unlisted video', async function () {
+ const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3)
- nonFederatedUnlistedVideoUUID = res.body.data[0].uuid
- })
+ expect(res.body.total).to.equal(3)
+ expect(res.body.data).to.have.lengthOf(3)
- it('Should be able to get non-federated unlisted video from origin', async function () {
- const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID)
+ nonFederatedUnlistedVideoUUID = res.body.data[0].uuid
+ })
- expect(res.body.name).to.equal('unlisted video')
- })
+ it('Should be able to get non-federated unlisted video from origin', async function () {
+ const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID)
- 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)
+ 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)
+ describe('Privacy update', function () {
- now = Date.now()
+ it('Should update the private and internal videos to public on server 1', async function () {
+ this.timeout(10000)
- {
- const attribute = {
- name: 'private video becomes public',
- privacy: VideoPrivacy.PUBLIC
- }
+ now = Date.now()
- await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
- }
+ {
+ const attribute = {
+ name: 'private video becomes public',
+ privacy: VideoPrivacy.PUBLIC
+ }
- {
- const attribute = {
- name: 'internal video becomes public',
- privacy: VideoPrivacy.PUBLIC
+ await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
}
- await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
- }
- await waitJobs(servers)
- })
+ {
+ const attribute = {
+ name: 'internal video becomes public',
+ privacy: VideoPrivacy.PUBLIC
+ }
+ await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
+ }
- 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)
+ await waitJobs(servers)
+ })
- 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')
+ 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)
- expect(privateVideo).to.not.be.undefined
- expect(internalVideo).to.not.be.undefined
+ 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(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).to.not.be.undefined
+ expect(internalVideo).to.not.be.undefined
- expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
- expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
- }
- })
+ 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)
- it('Should set these videos as private and internal', async function () {
- this.timeout(10000)
+ expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
+ expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
+ }
+ })
- 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 set these videos as private and internal', async function () {
+ this.timeout(10000)
- await waitJobs(servers)
+ await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, { privacy: VideoPrivacy.PRIVATE })
+ await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.INTERNAL })
- for (const server of servers) {
- const res = await getVideosList(server.url)
+ await waitJobs(servers)
- expect(res.body.total).to.equal(0)
- expect(res.body.data).to.have.lengthOf(0)
- }
+ 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
+ {
+ 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)
+ 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')
+ 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).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)
- }
+ expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL)
+ expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE)
+ }
+ })
})
after(async function () {
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,
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
{
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))
{
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))
{
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))
{
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))
{
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))
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,
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)
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
}
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
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)
+ }
}
})
})
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 () {
})
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)
+ }
+ }
})
})
}
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 () {
}
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 () {
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}" />`)
+ }
}
})
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}" />`)
+ }
}
})
})
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'
env: process.env,
lodash: _,
path,
- uuidv1,
- uuidv3,
- uuidv4,
- uuidv5,
cli,
logger,
constants,
video?: {
id: number
uuid: string
+ shortUUID: string
name?: string
url?: string
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'
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) {
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)
--- /dev/null
+export * from './result-list.model'
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'
}
video?: {
- id: number
+ id: number | string
startAt?: number
endAt?: number
}
--- /dev/null
+export * from './oauth-client-local.model'
export * from './video-update.model'
export * from './video.model'
+export * from './video-create-result.model'
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'
--- /dev/null
+export interface VideoPlaylistCreateResult {
+ id: number
+ uuid: string
+ shortUUID: string
+}
export interface VideoPlaylist {
id: number
uuid: string
+ shortUUID: string
+
isLocal: boolean
url: string
--- /dev/null
+export interface VideoCreateResult {
+ id: number
+ uuid: string
+ shortUUID: string
+}
export interface Video {
id: number
uuid: string
+ shortUUID: string
+
createdAt: Date | string
updatedAt: Date | string
publishedAt: Date | string
$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:
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
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
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:
$ref: '#/components/schemas/id'
uuid:
$ref: '#/components/schemas/UUIDv4'
+ shortUUID:
+ allOf:
+ - $ref: '#/components/schemas/shortUUID'
createdAt:
type: string
format: date-time
$ref: '#/components/schemas/Video/properties/id'
uuid:
$ref: '#/components/schemas/Video/properties/uuid'
+ shortUUID:
+ $ref: '#/components/schemas/Video/properties/shortUUID'
CommentThreadResponse:
properties:
total:
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"