]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Support short uuid for GET video/playlist
authorChocobozzz <me@florianbigard.com>
Mon, 28 Jun 2021 15:30:59 +0000 (17:30 +0200)
committerChocobozzz <chocobozzz@cpy.re>
Tue, 29 Jun 2021 12:56:35 +0000 (14:56 +0200)
94 files changed:
client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
client/src/app/+remote-interaction/remote-interaction.component.ts
client/src/app/+search/shared/abstract-lazy-load.resolver.ts
client/src/app/+search/shared/playlist-lazy-load.resolver.ts
client/src/app/+search/shared/video-lazy-load.resolver.ts
client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
client/src/app/+videos/+video-edit/video-update.component.html
client/src/app/+videos/+video-edit/video-update.component.ts
client/src/app/+videos/+video-watch/comment/video-comment.component.html
client/src/app/+videos/+video-watch/comment/video-comments.component.ts
client/src/app/+videos/+video-watch/video-watch.component.ts
client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
client/src/app/shared/shared-main/angular/link.component.ts
client/src/app/shared/shared-main/users/user-notification.model.ts
client/src/app/shared/shared-main/video/video.model.ts
client/src/app/shared/shared-share-modal/video-share.component.ts
client/src/app/shared/shared-thumbnail/video-thumbnail.component.ts
client/src/app/shared/shared-video-comment/video-comment.model.ts
client/src/app/shared/shared-video-comment/video-comment.service.ts
client/src/app/shared/shared-video-miniature/video-miniature.component.ts
client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.ts
client/src/app/shared/shared-video-playlist/video-playlist.model.ts
package.json
server/controllers/api/users/token.ts
server/controllers/api/video-playlist.ts
server/controllers/api/videos/live.ts
server/controllers/api/videos/upload.ts
server/helpers/custom-validators/misc.ts
server/helpers/image-utils.ts
server/helpers/uuid.ts [new file with mode: 0644]
server/initializers/migrations/0080-video-channels.ts
server/initializers/migrations/0345-video-playlists.ts
server/initializers/migrations/0560-user-feed-token.ts
server/lib/activitypub/actors/shared/object-to-model-attributes.ts
server/lib/client-html.ts
server/lib/local-actor.ts
server/lib/user.ts
server/middlewares/validators/abuse.ts
server/middlewares/validators/feeds.ts
server/middlewares/validators/index.ts
server/middlewares/validators/oembed.ts
server/middlewares/validators/redundancy.ts
server/middlewares/validators/shared/utils.ts
server/middlewares/validators/users.ts
server/middlewares/validators/videos/video-blacklist.ts
server/middlewares/validators/videos/video-captions.ts
server/middlewares/validators/videos/video-comments.ts
server/middlewares/validators/videos/video-live.ts
server/middlewares/validators/videos/video-ownership-changes.ts
server/middlewares/validators/videos/video-playlists.ts
server/middlewares/validators/videos/video-rates.ts
server/middlewares/validators/videos/video-shares.ts
server/middlewares/validators/videos/video-watch.ts
server/middlewares/validators/videos/videos.ts
server/models/video/formatter/video-format-utils.ts
server/models/video/video-caption.ts
server/models/video/video-playlist.ts
server/tests/api/activitypub/client.ts
server/tests/api/check-params/abuses.ts
server/tests/api/check-params/live.ts
server/tests/api/check-params/redundancy.ts
server/tests/api/check-params/users.ts
server/tests/api/check-params/video-blacklist.ts
server/tests/api/check-params/video-captions.ts
server/tests/api/check-params/video-comments.ts
server/tests/api/check-params/video-playlists.ts
server/tests/api/check-params/videos.ts
server/tests/api/notifications/moderation-notifications.ts
server/tests/api/notifications/user-notifications.ts
server/tests/api/server/handle-down.ts
server/tests/api/videos/video-playlists.ts
server/tests/api/videos/video-privacy.ts
server/tests/cli/prune-storage.ts
server/tests/client.ts
server/tools/peertube-repl.ts
shared/extra-utils/server/servers.ts
shared/extra-utils/videos/videos.ts
shared/models/common/index.ts [new file with mode: 0644]
shared/models/common/result-list.model.ts [moved from shared/models/result-list.model.ts with 100% similarity]
shared/models/index.ts
shared/models/moderation/abuse/abuse-create.model.ts
shared/models/tokens/index.ts [new file with mode: 0644]
shared/models/tokens/oauth-client-local.model.ts [moved from shared/models/oauth-client-local.model.ts with 100% similarity]
shared/models/videos/index.ts
shared/models/videos/playlist/index.ts
shared/models/videos/playlist/video-playlist-create-result.model.ts [new file with mode: 0644]
shared/models/videos/playlist/video-playlist.model.ts
shared/models/videos/video-create-result.model.ts [new file with mode: 0644]
shared/models/videos/video.model.ts
support/doc/api/openapi.yaml
yarn.lock

index 63143d0f985eb89607b7d99e93c63576294dde9c..08500ef5c10f8a68c37e7b0c5a6660ac3f0f03d6 100644 (file)
@@ -122,7 +122,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
   }
 
   getVideoUrl (videoBlock: VideoBlacklist) {
   }
 
   getVideoUrl (videoBlock: VideoBlacklist) {
-    return Video.buildClientUrl(videoBlock.video.uuid)
+    return Video.buildWatchUrl(videoBlock.video)
   }
 
   toHtml (text: string) {
   }
 
   toHtml (text: string) {
index bb9d705245ad80664c8a31dad9eb8341f5cbd24c..68254526a377c364b2b2301d47852996ac06ca92 100644 (file)
@@ -1,7 +1,7 @@
 import { SortMeta } from 'primeng/api'
 import { Component, OnInit } from '@angular/core'
 import { Notifier, RestPagination, RestTable } from '@app/core'
 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({
 import { VideoImport, VideoImportState } from '@shared/models'
 
 @Component({
@@ -55,11 +55,11 @@ export class MyVideoImportsComponent extends RestTable implements OnInit {
   }
 
   getVideoUrl (video: { uuid: string }) {
   }
 
   getVideoUrl (video: { uuid: string }) {
-    return '/w/' + video.uuid
+    return Video.buildWatchUrl(video)
   }
 
   getEditVideoUrl (video: { uuid: string }) {
   }
 
   getEditVideoUrl (video: { uuid: string }) {
-    return '/videos/update/' + video.uuid
+    return Video.buildUpdateUrl(video)
   }
 
   protected reloadData () {
   }
 
   protected reloadData () {
index 6ddf5b58da6c45ab47acef765c35102697745b29..293f7edad5506655b7de9f7d720366a5b52e27a5 100644 (file)
@@ -1,7 +1,7 @@
 import { forkJoin } from 'rxjs'
 import { Component, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 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({
 import { SearchService } from '@app/shared/shared-search'
 
 @Component({
@@ -39,7 +39,7 @@ export class RemoteInteractionComponent implements OnInit {
       if (videoResult.data.length !== 0) {
         const video = videoResult.data[0]
 
       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])
 
       } else if (channelResult.data.length !== 0) {
         const channel = new VideoChannel(channelResult.data[0])
 
index 31240f4514393f973d5c5d051d5b4b03c346ece9..b18a5b64d51ee07030e667ace19f232d83837fcd 100644 (file)
@@ -1,7 +1,7 @@
 import { Observable } from 'rxjs'
 import { map } from 'rxjs/operators'
 import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'
 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
 
 export abstract class AbstractLazyLoadResolver <T> implements Resolve<any> {
   protected router: Router
index 14ae798df86b4c5b93b38486226474157b373498..3310e9627162b6c4cd659064251b9c81a8f4d6c2 100644 (file)
@@ -19,6 +19,6 @@ export class PlaylistLazyLoadResolver extends AbstractLazyLoadResolver<VideoPlay
   }
 
   protected buildUrl (playlist: VideoPlaylist) {
   }
 
   protected buildUrl (playlist: VideoPlaylist) {
-    return '/w/p/' + playlist.uuid
+    return VideoPlaylist.buildWatchUrl(playlist)
   }
 }
   }
 }
index 12b5b2e82539fbed6127c55c81090ab162bd845d..69a3eb159af9b234047416ae667f0d9c4c1fe567 100644 (file)
@@ -19,6 +19,6 @@ export class VideoLazyLoadResolver extends AbstractLazyLoadResolver<Video> {
   }
 
   protected buildUrl (video: Video) {
   }
 
   protected buildUrl (video: Video) {
-    return '/w/' + video.uuid
+    return Video.buildWatchUrl(video)
   }
 }
   }
 }
index 4c39b276a583dafb68d65a93c862c6eca85c5f50..01c9fcb1626f98d77c1bc740169c2a242cfc6c4a 100644 (file)
@@ -1,11 +1,11 @@
 
 import { forkJoin } from 'rxjs'
 
 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 { 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'
 import { LiveVideoService } from '@app/shared/shared-video-live'
 import { LoadingBarService } from '@ngx-loading-bar/core'
 import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy } from '@shared/models'
@@ -127,7 +127,7 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
       () => {
         this.notifier.success($localize`Live published.`)
 
       () => {
         this.notifier.success($localize`Live published.`)
 
-        this.router.navigate(['/w', video.uuid])
+        this.router.navigateByUrl(Video.buildWatchUrl(video))
       },
 
       err => {
       },
 
       err => {
index f383662a1a9c1358fd7d78a984eb43c283fb74b1..ec027f257e98b7583312063b7cca14742a89bc48 100644 (file)
@@ -1,16 +1,16 @@
+import { UploadState, UploadxOptions, UploadxService } from 'ngx-uploadx'
+import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
 import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
 import { Router } from '@angular/router'
 import { 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 { 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 { 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 { 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 { VideoSend } from './video-send'
-import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
 
 @Component({
   selector: 'my-video-upload',
 
 @Component({
   selector: 'my-video-upload',
@@ -243,7 +243,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
             this.isUploadingVideo = false
 
             this.notifier.success($localize`Video published.`)
             this.isUploadingVideo = false
 
             this.notifier.success($localize`Video published.`)
-            this.router.navigate([ '/w', video.uuid ])
+            this.router.navigateByUrl(Video.buildWatchUrl(video))
           },
 
           err => {
           },
 
           err => {
index 9629081e361c3c992e51329d735dca7124c9a12f..33e3ddd143862f1aac65b72d0aed9d19c7977a15 100644 (file)
@@ -1,7 +1,7 @@
 <div class="margin-content">
   <div class="title-page title-page-single">
     <span class="mr-1" i18n>Update</span>
 <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">
   </div>
 
   <form novalidate [formGroup]="form">
index 574669a23731b54616ed80a911deb77597568e95..1534eee82f80c3a68d4ae446dbe18fdf0ec5ee13 100644 (file)
@@ -5,7 +5,7 @@ import { Component, HostListener, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { Notifier } from '@app/core'
 import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
 import { 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'
 import { LiveVideoService } from '@app/shared/shared-video-live'
 import { LoadingBarService } from '@ngx-loading-bar/core'
 import { LiveVideo, LiveVideoUpdate, VideoPrivacy } from '@shared/models'
@@ -156,7 +156,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
             this.isUpdatingVideo = false
             this.loadingBar.useRef().complete()
             this.notifier.success($localize`Video updated.`)
             this.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 => {
           },
 
           err => {
@@ -175,4 +175,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
       pluginData: this.video.pluginData
     })
   }
       pluginData: this.video.pluginData
     })
   }
+
+  getVideoUrl () {
+    return Video.buildWatchUrl(this.videoDetails)
+  }
 }
 }
index 06548edc822c66d9c87ffe9448edf0cf3505ca65..d8b944b354d9e55a8ff4dedd0fb8958098563f70 100644 (file)
@@ -20,7 +20,7 @@
             </a>
           </div>
 
             </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>
             {{ comment.createdAt | myFromNow }}
           </a>
         </div>
@@ -45,7 +45,7 @@
       <ng-container *ngIf="comment.isDeleted">
         <div class="comment-account-date">
           <span class="comment-account" i18n>Deleted</span>
       <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>
 
              class="comment-date">{{ comment.createdAt | myFromNow }}</a>
         </div>
 
index 210236b61133856fe23f56afdb8737f75a484b47..2c39e63fbd372526ef483a604e0a3518000a3f0b 100644 (file)
@@ -247,7 +247,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
       this.componentPagination.totalItems = null
       this.totalNotDeletedComments = null
 
       this.componentPagination.totalItems = null
       this.totalNotDeletedComments = null
 
-      this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video.uuid)
+      this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video)
       this.loadMoreThreads()
     }
   }
       this.loadMoreThreads()
     }
   }
index a444dc51f8feea704e5b1b11423e7bf163ab5c4f..12b0baebe77486121d50cf44b50d456134f562b0 100644 (file)
@@ -312,7 +312,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
   getVideoUrl () {
     if (!this.video.url) {
 
   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
   }
     }
     return this.video.url
   }
@@ -415,7 +415,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
   private loadVideo (videoId: string) {
     // Video did not change
 
   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()
 
 
     if (this.player) this.player.pause()
 
@@ -489,7 +492,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
   private loadPlaylist (playlistId: string) {
     // Playlist did not change
 
   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(
 
     this.playlistService.getVideoPlaylist(playlistId)
       .pipe(
@@ -772,13 +778,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
   private flushPlayer () {
     // Remove player if it exists
 
   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)
     }
   }
 
     }
   }
 
index 07b9dddba01335b3958322bc7014b3de348959f7..67aa0e39955fcc70d15f562da733843b0cc51975 100644 (file)
@@ -116,11 +116,11 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
   }
 
   getVideoUrl (abuse: AdminAbuse) {
   }
 
   getVideoUrl (abuse: AdminAbuse) {
-    return Video.buildClientUrl(abuse.video.uuid)
+    return Video.buildWatchUrl(abuse.video)
   }
 
   getCommentUrl (abuse: AdminAbuse) {
   }
 
   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) {
   }
 
   getAccountUrl (abuse: ProcessedAbuse) {
index 76d1201b90467c3d4113a82b5c96e6bbc999e0a1..597a16871f5de71e484280c8473b046a94a93cb9 100644 (file)
@@ -6,7 +6,7 @@ import { Component, Input, ViewEncapsulation } from '@angular/core'
   templateUrl: './link.component.html'
 })
 export class LinkComponent {
   templateUrl: './link.component.html'
 })
 export class LinkComponent {
-  @Input() internalLink?: any[]
+  @Input() internalLink?: string | any[]
 
   @Input() href?: string
   @Input() target?: string
 
   @Input() href?: string
   @Input() target?: string
index c80bc13b0d92ffb5a8e40c1f69359fcf101a31bc..4c15eb98186ecc5fbdd0bc0f398ef60344d698dc 100644 (file)
@@ -12,6 +12,7 @@ import {
   UserRight,
   VideoInfo
 } from '@shared/models'
   UserRight,
   VideoInfo
 } from '@shared/models'
+import { Video } from '../video'
 
 export class UserNotification implements UserNotificationServer {
   id: number
 
 export class UserNotification implements UserNotificationServer {
   id: number
@@ -238,7 +239,7 @@ export class UserNotification implements UserNotificationServer {
   }
 
   private buildVideoUrl (video: { uuid: string }) {
   }
 
   private buildVideoUrl (video: { uuid: string }) {
-    return '/w/' + video.uuid
+    return Video.buildWatchUrl(video)
   }
 
   private buildAccountUrl (account: { name: string, host: string }) {
   }
 
   private buildAccountUrl (account: { name: string, host: string }) {
index ab8ed905142bd43c63d17c9f99152eeb9a1a993e..f0a4a3f37c031a9a7b33797d31ed2209e1750ec5 100644 (file)
@@ -26,12 +26,18 @@ export class Video implements VideoServerModel {
   licence: VideoConstant<number>
   language: VideoConstant<string>
   privacy: VideoConstant<VideoPrivacy>
   licence: VideoConstant<number>
   language: VideoConstant<string>
   privacy: VideoConstant<VideoPrivacy>
+
   description: string
   description: string
+
   duration: number
   durationLabel: string
   duration: number
   durationLabel: string
+
   id: number
   uuid: string
   id: number
   uuid: string
+  shortUUID: string
+
   isLocal: boolean
   isLocal: boolean
+
   name: string
   serverHost: string
   thumbnailPath: string
   name: string
   serverHost: string
   thumbnailPath: string
@@ -85,8 +91,12 @@ export class Video implements VideoServerModel {
 
   pluginData?: any
 
 
   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 = {}) {
   }
 
   constructor (hash: VideoServerModel, translations = {}) {
@@ -109,6 +119,7 @@ export class Video implements VideoServerModel {
 
     this.id = hash.id
     this.uuid = hash.uuid
 
     this.id = hash.id
     this.uuid = hash.uuid
+    this.shortUUID = hash.shortUUID
 
     this.isLocal = hash.isLocal
     this.name = hash.name
 
     this.isLocal = hash.isLocal
     this.name = hash.name
index 2a73e6166dd028fd532b744947024e288eda9589..a41ff248b1e6ea3ce954a955bfcbc95025b3e23c 100644 (file)
@@ -1,5 +1,5 @@
 import { Component, ElementRef, Input, ViewChild } from '@angular/core'
 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'
 import { VideoPlaylist } from '@app/shared/shared-video-playlist'
 import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
 import { VideoCaption } from '@shared/models'
@@ -98,14 +98,15 @@ export class VideoShareComponent {
 
   getVideoUrl () {
     let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin
 
   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 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
 
 
     if (!this.includeVideoInPlaylist) return base
 
index d5583c29fc926e85abf942fb01be608766c0c5e7..ad5d30db2aaf3ef088ff21bd6f5eb85db3de4c87 100644 (file)
@@ -12,7 +12,7 @@ export class VideoThumbnailComponent {
   @Input() video: Video
   @Input() nsfw = false
 
   @Input() video: Video
   @Input() nsfw = false
 
-  @Input() videoRouterLink: any[]
+  @Input() videoRouterLink: string | any[]
   @Input() queryParams: { [ p: string ]: any }
   @Input() videoHref: string
   @Input() videoTarget: string
   @Input() queryParams: { [ p: string ]: any }
   @Input() videoHref: string
   @Input() videoTarget: string
@@ -57,7 +57,7 @@ export class VideoThumbnailComponent {
   getVideoRouterLink () {
     if (this.videoRouterLink) return this.videoRouterLink
 
   getVideoRouterLink () {
     if (this.videoRouterLink) return this.videoRouterLink
 
-    return [ '/w', this.video.uuid ]
+    return Video.buildWatchUrl(this.video)
   }
 
   onWatchLaterClick (event: Event) {
   }
 
   onWatchLaterClick (event: Event) {
index 94d6c5fa8c879e951805f2b6ba8e409cbda51192..ba0f57e8fe20d8b266752bd563674f18866b15bf 100644 (file)
@@ -1,5 +1,5 @@
 import { getAbsoluteAPIUrl } from '@app/helpers'
 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 {
 import { Account as AccountInterface, VideoComment as VideoCommentServerModel, VideoCommentAdmin as VideoCommentAdminServerModel } from '@shared/models'
 
 export class VideoComment implements VideoCommentServerModel {
@@ -85,7 +85,7 @@ export class VideoCommentAdmin implements VideoCommentAdminServerModel {
       id: hash.video.id,
       uuid: hash.video.uuid,
       name: hash.video.name,
       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
     }
 
     this.localUrl = this.video.localUrl + ';threadId=' + this.threadId
index c5aeb3c12e86ec24e6df9b46b29d172e1adb3f21..4f1452116a75fa6d0bb7db832fcc30078457ac89 100644 (file)
@@ -9,6 +9,7 @@ import {
   FeedFormat,
   ResultList,
   ThreadsResultList,
   FeedFormat,
   ResultList,
   ThreadsResultList,
+  Video,
   VideoComment as VideoCommentServerModel,
   VideoCommentAdmin,
   VideoCommentCreate,
   VideoComment as VideoCommentServerModel,
   VideoCommentAdmin,
   VideoCommentCreate,
@@ -127,7 +128,7 @@ export class VideoCommentService {
       )
   }
 
       )
   }
 
-  getVideoCommentsFeeds (videoUUID?: string) {
+  getVideoCommentsFeeds (video: Pick<Video, 'uuid'>) {
     const feeds = [
       {
         format: FeedFormat.RSS,
     const feeds = [
       {
         format: FeedFormat.RSS,
@@ -146,9 +147,9 @@ export class VideoCommentService {
       }
     ]
 
       }
     ]
 
-    if (videoUUID !== undefined) {
+    if (video !== undefined) {
       for (const feed of feeds) {
       for (const feed of feeds) {
-        feed.url += '?videoId=' + videoUUID
+        feed.url += '?videoId=' + video.uuid
       }
     }
 
       }
     }
 
index fe161c977e51c31f3453b1fc001f1e30092eaf6b..67e0de6a2156cb1f7def2eadac6173b3f4bf6e9a 100644 (file)
@@ -85,7 +85,7 @@ export class VideoMiniatureComponent implements OnInit {
     playlistElementId?: number
   }
 
     playlistElementId?: number
   }
 
-  videoRouterLink: any[] = []
+  videoRouterLink: string | any[] = []
   videoHref: string
   videoTarget: string
 
   videoHref: string
   videoTarget: string
 
@@ -120,7 +120,7 @@ export class VideoMiniatureComponent implements OnInit {
 
   buildVideoLink () {
     if (this.videoLinkType === 'internal' || !this.video.url) {
 
   buildVideoLink () {
     if (this.videoLinkType === 'internal' || !this.video.url) {
-      this.videoRouterLink = [ '/w', this.video.uuid ]
+      this.videoRouterLink = Video.buildWatchUrl(this.video)
       return
     }
 
       return
     }
 
index 57eab4dfdb04e66f51139df16ca688c4c7e73bde..d99170e4e236913b4fcade137612778912bca6fa 100644 (file)
@@ -66,7 +66,7 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
   buildRouterLink () {
     if (!this.playlist) return null
 
   buildRouterLink () {
     if (!this.playlist) return null
 
-    return [ '/w/p', this.playlist.uuid ]
+    return VideoPlaylist.buildWatchUrl(this.playlist)
   }
 
   buildRouterQuery () {
   }
 
   buildRouterQuery () {
index 8de5092a95c6b61cf11d05025895822c66787b23..c80ea2e6b0f2cb8fe9931b0b1b4b173a7f400204 100644 (file)
@@ -39,7 +39,7 @@ export class VideoPlaylistMiniatureComponent implements OnInit {
     }
 
     if (this.linkType === 'internal' || !this.playlist.url) {
     }
 
     if (this.linkType === 'internal' || !this.playlist.url) {
-      this.routerLink = [ '/w/p', this.playlist.uuid ]
+      this.routerLink = VideoPlaylist.buildWatchUrl(this.playlist)
       return
     }
 
       return
     }
 
index d67f372f41e7b101bd1dfb6f656770e98c159cfa..d96b7092203c5e84dd320ee2b6ce4e811cefbd69 100644 (file)
@@ -13,6 +13,8 @@ import {
 export class VideoPlaylist implements ServerVideoPlaylist {
   id: number
   uuid: string
 export class VideoPlaylist implements ServerVideoPlaylist {
   id: number
   uuid: string
+  shortUUID: string
+
   isLocal: boolean
 
   url: string
   isLocal: boolean
 
   url: string
@@ -41,11 +43,17 @@ export class VideoPlaylist implements ServerVideoPlaylist {
 
   videoChannelBy?: 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
   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
 
     this.url = hash.url
     this.isLocal = hash.isLocal
 
index 9fa1e4a0f6ee62d5b08741687787da188a7d56c8..dcecd3940019ff0da676b6cc8920776cd71c8228 100644 (file)
     "sanitize-html": "2.x",
     "sequelize": "6.6.2",
     "sequelize-typescript": "^2.0.0-beta.1",
     "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",
     "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",
     "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",
     "validator": "^13.0.0",
     "webfinger.js": "^2.6.6",
     "webtorrent": "^1.0.0",
index e636f44f6c85c3fb7ca6f3333cd0fcaf575e6e35..b405ddbf41f586e4a1a47d6b861a2768ffb243cd 100644 (file)
@@ -1,7 +1,7 @@
 import * as express from 'express'
 import * as RateLimit from 'express-rate-limit'
 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 { 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'
 import { CONFIG } from '@server/initializers/config'
 import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth'
 import { handleOAuthToken } from '@server/lib/auth/oauth'
@@ -107,7 +107,7 @@ function getScopedTokens (req: express.Request, res: express.Response) {
 async function renewScopedTokens (req: express.Request, res: express.Response) {
   const user = res.locals.oauth.token.user
 
 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({
   await user.save()
 
   return res.json({
index 5c4aa50ace938cb2de63a1ac9c1a60903da657c3..87a6f6bbee4a94c790ba63df586e255fe50453a6 100644 (file)
@@ -1,6 +1,8 @@
 import * as express from 'express'
 import { join } from 'path'
 import * as express from 'express'
 import { join } from 'path'
+import { uuidToShort } from '@server/helpers/uuid'
 import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists'
 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 { getServerActor } from '@server/models/application/application'
 import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
 import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
@@ -43,7 +45,6 @@ import {
 import { AccountModel } from '../../models/account/account'
 import { VideoPlaylistModel } from '../../models/video/video-playlist'
 import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
 import { 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 })
 
 
 const reqThumbnailFile = createReqFiles([ 'thumbnailfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { thumbnailfile: CONFIG.STORAGE.TMP_DIR })
 
@@ -199,6 +200,7 @@ async function addVideoPlaylist (req: express.Request, res: express.Response) {
   return res.json({
     videoPlaylist: {
       id: videoPlaylistCreated.id,
   return res.json({
     videoPlaylist: {
       id: videoPlaylistCreated.id,
+      shortUUID: uuidToShort(videoPlaylistCreated.uuid),
       uuid: videoPlaylistCreated.uuid
     }
   })
       uuid: videoPlaylistCreated.uuid
     }
   })
index 61fa979c47919a261350b116af4f152e8478b06b..d8c51c2d41b5c87e54d3ea3b6ddd6428eb267eea 100644 (file)
@@ -1,6 +1,6 @@
 import * as express from 'express'
 import * as express from 'express'
-import { v4 as uuidv4 } from 'uuid'
 import { createReqFiles } from '@server/helpers/express-utils'
 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 { CONFIG } from '@server/initializers/config'
 import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants'
 import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
@@ -11,12 +11,12 @@ import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator
 import { VideoLiveModel } from '@server/models/video/video-live'
 import { MVideoDetails, MVideoFullLight } from '@server/types/models'
 import { LiveVideoCreate, LiveVideoUpdate, VideoState } from '../../../../shared'
 import { 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 { 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 liveRouter = express.Router()
 
@@ -94,7 +94,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
   const videoLive = new VideoLiveModel()
   videoLive.saveReplay = videoInfo.saveReplay || false
   videoLive.permanentLive = videoInfo.permanentLive || false
   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,
 
   const [ thumbnailModel, previewModel ] = await buildVideoThumbnailsFromReq({
     video,
@@ -138,6 +138,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
   return res.json({
     video: {
       id: videoCreated.id,
   return res.json({
     video: {
       id: videoCreated.id,
+      shortUUID: uuidToShort(videoCreated.uuid),
       uuid: videoCreated.uuid
     }
   })
       uuid: videoCreated.uuid
     }
   })
index e767492bc1a0a661cf559e307053362bd150af93..bcd21ac9987eeb83b40febb92cac7f475af3f507 100644 (file)
@@ -2,6 +2,7 @@ import * as express from 'express'
 import { move } from 'fs-extra'
 import { getLowercaseExtension } from '@server/helpers/core-utils'
 import { deleteResumableUploadMetaFile, getResumableUploadPath } from '@server/helpers/upload'
 import { 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'
 import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
 import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
 import { addOptimizeOrMergeAudioJob, buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
@@ -218,6 +219,7 @@ async function addVideo (options: {
   return res.json({
     video: {
       id: videoCreated.id,
   return res.json({
     video: {
       id: videoCreated.id,
+      shortUUID: uuidToShort(videoCreated.uuid),
       uuid: videoCreated.uuid
     }
   })
       uuid: videoCreated.uuid
     }
   })
index 229e9f03c07a4135e46a7a8e66a6729126847bcf..528bfcfb851eec54d815177402ae0860c8e4c9eb 100644 (file)
@@ -2,6 +2,7 @@ import 'multer'
 import { UploadFilesForCheck } from 'express'
 import { sep } from 'path'
 import validator from 'validator'
 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
 
 function exists (value: any) {
   return value !== undefined && value !== null
@@ -50,42 +51,7 @@ function isIntOrNull (value: any) {
   return value === null || validator.isInt('' + value)
 }
 
   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 isFileFieldValid (
   files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
@@ -160,6 +126,51 @@ function isFileValid (
 
 // ---------------------------------------------------------------------------
 
 
 // ---------------------------------------------------------------------------
 
+function toCompleteUUID (value: string) {
+  if (isShortUUID(value)) return shortToUUID(value)
+
+  return value
+}
+
+function toIntOrNull (value: string) {
+  const v = toValueOrNull(value)
+
+  if (v === null || v === undefined) return v
+  if (typeof v === 'number') return v
+
+  return validator.toInt('' + v)
+}
+
+function toBooleanOrNull (value: any) {
+  const v = toValueOrNull(value)
+
+  if (v === null || v === undefined) return v
+  if (typeof v === 'boolean') return v
+
+  return validator.toBoolean('' + v)
+}
+
+function toValueOrNull (value: string) {
+  if (value === 'null') return null
+
+  return value
+}
+
+function toArray (value: any) {
+  if (value && isArray(value) === false) return [ value ]
+
+  return value
+}
+
+function toIntArray (value: any) {
+  if (!value) return []
+  if (isArray(value) === false) return [ validator.toInt(value) ]
+
+  return value.map(v => validator.toInt(v))
+}
+
+// ---------------------------------------------------------------------------
+
 export {
   exists,
   isArrayOf,
 export {
   exists,
   isArrayOf,
@@ -169,6 +180,7 @@ export {
   isIdValid,
   isSafePath,
   isUUIDValid,
   isIdValid,
   isSafePath,
   isUUIDValid,
+  toCompleteUUID,
   isIdOrUUIDValid,
   isDateValid,
   toValueOrNull,
   isIdOrUUIDValid,
   isDateValid,
   toValueOrNull,
index 122fb009d1950b10f644e26d0e42463d255668eb..c76ed545bb2b2bdba91fe33183cd6d2567cfda4b 100644 (file)
@@ -1,12 +1,12 @@
 import { copy, readFile, remove, rename } from 'fs-extra'
 import * as Jimp from 'jimp'
 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 { getLowercaseExtension } from './core-utils'
 import { convertWebPToJPG, processGIF } from './ffmpeg-utils'
 import { logger } from './logger'
+import { buildUUID } from './uuid'
 
 function generateImageFilename (extension = '.jpg') {
 
 function generateImageFilename (extension = '.jpg') {
-  return uuidv4() + extension
+  return buildUUID() + extension
 }
 
 async function processImage (
 }
 
 async function processImage (
diff --git a/server/helpers/uuid.ts b/server/helpers/uuid.ts
new file mode 100644 (file)
index 0000000..3eb06c7
--- /dev/null
@@ -0,0 +1,32 @@
+import * as short from 'short-uuid'
+
+const translator = short()
+
+function buildUUID () {
+  return short.uuid()
+}
+
+function uuidToShort (uuid: string) {
+  if (!uuid) return uuid
+
+  return translator.fromUUID(uuid)
+}
+
+function shortToUUID (shortUUID: string) {
+  if (!shortUUID) return shortUUID
+
+  return translator.toUUID(shortUUID)
+}
+
+function isShortUUID (value: string) {
+  if (!value) return false
+
+  return value.length === translator.maxLength
+}
+
+export {
+  buildUUID,
+  uuidToShort,
+  shortToUUID,
+  isShortUUID
+}
index 883224cb02e929a78766b56c197b26e2cfa23dcf..0e6952350260906c49261829590d42a471b63f22 100644 (file)
@@ -1,5 +1,5 @@
+import { buildUUID } from '@server/helpers/uuid'
 import * as Sequelize from 'sequelize'
 import * as Sequelize from 'sequelize'
-import { v4 as uuidv4 } from 'uuid'
 
 async function up (utils: {
   transaction: Sequelize.Transaction
 
 async function up (utils: {
   transaction: Sequelize.Transaction
@@ -23,7 +23,7 @@ async function up (utils: {
   {
     const authors = await utils.db.Author.findAll()
     for (const author of authors) {
   {
     const authors = await utils.db.Author.findAll()
     for (const author of authors) {
-      author.uuid = uuidv4()
+      author.uuid = buildUUID()
       await author.save()
     }
   }
       await author.save()
     }
   }
index 89a14a6eef286285245491e72eacee663090207f..8dd631dff78c52f9218a4df534d8e6dc5a0977a2 100644 (file)
@@ -1,6 +1,6 @@
 import * as Sequelize from 'sequelize'
 import * as Sequelize from 'sequelize'
+import { buildUUID } from '@server/helpers/uuid'
 import { VideoPlaylistPrivacy, VideoPlaylistType } from '../../../shared/models/videos'
 import { VideoPlaylistPrivacy, VideoPlaylistType } from '../../../shared/models/videos'
-import { v4 as uuidv4 } from 'uuid'
 import { WEBSERVER } from '../constants'
 
 async function up (utils: {
 import { WEBSERVER } from '../constants'
 
 async function up (utils: {
@@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS "videoPlaylistElement"
     const usernames = userResult.map(r => r.username)
 
     for (const username of usernames) {
     const 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 = `
 
       const baseUrl = WEBSERVER.URL + '/video-playlists/' + uuid
       const query = `
index 7c61def17d2318a67fb60677059ca8f6d290d8e0..0423013522a3e9be327be8ccabe99f81ce2c4df9 100644 (file)
@@ -1,5 +1,5 @@
 import * as Sequelize from 'sequelize'
 import * as Sequelize from 'sequelize'
-import { v4 as uuidv4 } from 'uuid'
+import { buildUUID } from '@server/helpers/uuid'
 
 async function up (utils: {
   transaction: Sequelize.Transaction
 
 async function up (utils: {
   transaction: Sequelize.Transaction
@@ -26,7 +26,7 @@ async function up (utils: {
     const users = await utils.sequelize.query<any>(query, options)
 
     for (const user of users) {
     const 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)
     }
   }
       await utils.sequelize.query(queryUpdate)
     }
   }
index f53b98448cf6f98b9ef0ecc2a6d2c90ea039bfcf..1612b3ad0cc0bb946466233865b73a7f0225038f 100644 (file)
@@ -1,6 +1,6 @@
-import { v4 as uuidv4 } from 'uuid'
 import { getLowercaseExtension } from '@server/helpers/core-utils'
 import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
 import { 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'
 import { MIMETYPES } from '@server/initializers/constants'
 import { ActorModel } from '@server/models/actor/actor'
 import { FilteredModelAttributes } from '@server/types'
@@ -51,7 +51,7 @@ function getImageInfoFromObject (actorObject: ActivityPubActor, type: ActorImage
   if (!extension) return undefined
 
   return {
   if (!extension) return undefined
 
   return {
-    name: uuidv4() + extension,
+    name: buildUUID() + extension,
     fileUrl: icon.url,
     height: icon.height,
     width: icon.width,
     fileUrl: icon.url,
     height: icon.height,
     width: icon.width,
index 0191b55ef0844a60bcc1b42c454695394ae981e8..72194416dec8c9acb8825e90665642c3ff293b9e 100644 (file)
@@ -27,6 +27,7 @@ import { VideoChannelModel } from '../models/video/video-channel'
 import { VideoPlaylistModel } from '../models/video/video-playlist'
 import { MAccountActor, MChannelActor } from '../types/models'
 import { ServerConfigManager } from './server-config-manager'
 import { 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
 
 type Tags = {
   ogType: string
@@ -78,7 +79,9 @@ class ClientHtml {
     return customHtml
   }
 
     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)
     // Let Angular application handle errors
     if (!validator.isInt(videoId) && !validator.isUUID(videoId, 4)) {
       res.status(HttpStatusCode.NOT_FOUND_404)
@@ -136,7 +139,9 @@ class ClientHtml {
     return customHtml
   }
 
     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)
     // Let Angular application handle errors
     if (!validator.isInt(videoPlaylistId) && !validator.isUUID(videoPlaylistId, 4)) {
       res.status(HttpStatusCode.NOT_FOUND_404)
index 2d2bd43a162f77bf25413242c6b99794b6d3e522..77667f6b0bfb51f2428b0e2dd20ad760f9f2d342 100644 (file)
@@ -2,8 +2,8 @@ import 'multer'
 import { queue } from 'async'
 import * as LRUCache from 'lru-cache'
 import { join } from 'path'
 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 { 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'
 import { ActorModel } from '@server/models/actor/actor'
 import { ActivityPubActorType, ActorImageType } from '@shared/models'
 import { retryTransactionWrapper } from '../helpers/database-utils'
@@ -44,7 +44,7 @@ async function updateLocalActorImageFile (
 
   const extension = getLowercaseExtension(imagePhysicalFile.filename)
 
 
   const 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)
 
   const destination = join(CONFIG.STORAGE.ACTOR_IMAGES, imageName)
   await processImage(imagePhysicalFile.path, destination, imageSize)
 
index 8820e82431538ab8bb4ad3ee2f436e7fe7d9e332..936403692c79ebc15fee2573beb9de9d9a6e2f5e 100644 (file)
@@ -1,5 +1,5 @@
 import { Transaction } from 'sequelize/types'
 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'
 import { UserModel } from '@server/models/user/user'
 import { MActorDefault } from '@server/types/models/actor'
 import { ActivityPubActorType } from '../../shared/models/activitypub'
@@ -210,7 +210,7 @@ async function buildChannelAttributes (user: MUser, transaction?: Transaction, c
 
   // Conflict, generate uuid instead
   const actor = await ActorModel.loadLocalByName(channelName, transaction)
 
   // 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`
 
 
   const videoChannelDisplayName = `Main ${user.username} channel`
 
index 56c97747cefa7a810f6ef8b33a71152eefafccea..c048bc6af344c899b750d762aee9813f76f49385 100644 (file)
@@ -12,7 +12,7 @@ import {
   isAbuseTimestampValid,
   isAbuseVideoIsValid
 } from '@server/helpers/custom-validators/abuses'
   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'
 import { logger } from '@server/helpers/logger'
 import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
 import { AbuseCreate, UserRight } from '@shared/models'
@@ -27,6 +27,7 @@ const abuseReportValidator = [
 
   body('video.id')
     .optional()
 
   body('video.id')
     .optional()
+    .customSanitizer(toCompleteUUID)
     .custom(isIdOrUUIDValid)
     .withMessage('Should have a valid videoId'),
   body('video.startAt')
     .custom(isIdOrUUIDValid)
     .withMessage('Should have a valid videoId'),
   body('video.startAt')
index 51e6d6fffde91a48e53afb2462591d0ff1720d44..51b8fdd19bbc771d207f5452aa888be7257a0a77 100644 (file)
@@ -1,8 +1,9 @@
 import * as express from 'express'
 import { param, query } from 'express-validator'
 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 { 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,
 import { logger } from '../../helpers/logger'
 import {
   areValidationErrors,
@@ -98,7 +99,10 @@ const videoSubscriptionFeedsValidator = [
 ]
 
 const videoCommentsFeedsValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking feeds parameters', { parameters: req.query })
index 24faeea3efdb272d583c3c5186693cf7dfddbac2..94a3c2deae199c2cec1e50486b663dbee16b6697 100644 (file)
@@ -11,7 +11,7 @@ export * from './sort'
 export * from './users'
 export * from './user-subscriptions'
 export * from './videos'
 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 './search'
 export * from './server'
 export * from './user-history'
+export * from './webfinger'
index e1015d7fdd4d011bf047e13ca9fa5d9e81052b33..0a82e6932d77dd1b95d4c2fea4a55113705f6fe8 100644 (file)
@@ -6,7 +6,7 @@ import { VideoPlaylistModel } from '@server/models/video/video-playlist'
 import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
 import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
 import { isTestInstance } from '../../helpers/core-utils'
 import { 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'
 import { logger } from '../../helpers/logger'
 import { WEBSERVER } from '../../initializers/constants'
 import { areValidationErrors } from './shared'
@@ -79,7 +79,7 @@ const oembedValidator = [
       })
     }
 
       })
     }
 
-    const elementId = matches[1]
+    const elementId = toCompleteUUID(matches[1])
     if (isIdOrUUIDValid(elementId) === false) {
       return res.fail({ message: 'Invalid video or playlist id.' })
     }
     if (isIdOrUUIDValid(elementId) === false) {
       return res.fail({ message: 'Invalid video or playlist id.' })
     }
index da24f4c9b73d0033e24be16f14f579768efebbf7..116c8c611188ac748858bf23ad5da6d61591a2ac 100644 (file)
@@ -2,15 +2,24 @@ import * as express from 'express'
 import { body, param, query } from 'express-validator'
 import { isVideoRedundancyTarget } from '@server/helpers/custom-validators/video-redundancies'
 import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
 import { 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 { 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 = [
 
 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'),
   param('resolution')
     .customSanitizer(toIntOrNull)
     .custom(exists).withMessage('Should have a valid resolution'),
@@ -56,9 +65,8 @@ const videoFileRedundancyGetValidator = [
 ]
 
 const videoPlaylistRedundancyGetValidator = [
 ]
 
 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'),
   param('streamingPlaylistType')
     .customSanitizer(toIntOrNull)
     .custom(exists).withMessage('Should have a valid streaming playlist type'),
@@ -135,7 +143,8 @@ const listVideoRedundanciesValidator = [
 
 const addVideoRedundancyValidator = [
   body('videoId')
 
 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) => {
     .withMessage('Should have a valid video id'),
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
index d3e4870a92eba9dc1dc912291151a1a69db48b47..4f08560af5f79ef37c3626f8de09a5f9fad2c014 100644 (file)
@@ -1,5 +1,6 @@
 import * as express from 'express'
 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) {
 import { logger } from '../../../helpers/logger'
 
 function areValidationErrors (req: express.Request, res: express.Response) {
@@ -41,10 +42,24 @@ function createSortableColumns (sortableColumns: string[]) {
   return sortableColumns.concat(sortableColumnDesc)
 }
 
   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,
 // ---------------------------------------------------------------------------
 
 export {
   areValidationErrors,
   checkSort,
-  createSortableColumns
+  createSortableColumns,
+  isValidVideoIdParam,
+  isValidPlaylistIdParam
 }
 }
index 218633b8da525cb60699acf6e4c85d82163249a7..698d7d814b7a7daf72c592be9f26c133c5356561 100644 (file)
@@ -7,7 +7,7 @@ import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-code
 import { UserRole } from '../../../shared/models/users'
 import { UserRegister } from '../../../shared/models/users/user-register.model'
 import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
 import { 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 { isThemeNameValid } from '../../helpers/custom-validators/plugins'
 import {
   isNoInstanceConfigWarningModal,
@@ -35,7 +35,7 @@ import { Redis } from '../../lib/redis'
 import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup'
 import { ActorModel } from '../../models/actor/actor'
 import { UserModel } from '../../models/user/user'
 import { 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 usersListValidator = [
   query('blocked')
@@ -302,7 +302,7 @@ const usersGetValidator = [
 ]
 
 const usersVideoRatingValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking usersVideoRating parameters', { parameters: req.params })
index 7374ba774c1d7271e68cc1124603562fc19ce5e3..21141d84d1204f009fbd4c7fa6e7b6e91b3521c5 100644 (file)
@@ -1,13 +1,13 @@
 import * as express from 'express'
 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 { 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 { 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 = [
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
@@ -21,7 +21,8 @@ const videosBlacklistRemoveValidator = [
 ]
 
 const videosBlacklistAddValidator = [
 ]
 
 const videosBlacklistAddValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
+  isValidVideoIdParam('videoId'),
+
   body('unfederate')
     .optional()
     .customSanitizer(toBooleanOrNull)
   body('unfederate')
     .optional()
     .customSanitizer(toBooleanOrNull)
@@ -49,7 +50,8 @@ const videosBlacklistAddValidator = [
 ]
 
 const videosBlacklistUpdateValidator = [
 ]
 
 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'),
   body('reason')
     .optional()
     .custom(isVideoBlacklistReasonValid).withMessage('Should have a valid reason'),
index 2295e049afe9376b665411951d0a11959a0e506d..2946f3e1511a55a4325ffe1a2d3a701db45edb26 100644 (file)
@@ -1,16 +1,18 @@
 import * as express from 'express'
 import { body, param } from 'express-validator'
 import { UserRight } from '../../../../shared'
 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 { 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 = [
 
 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(
   body('captionfile')
     .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
     .withMessage(
@@ -34,8 +36,10 @@ const addVideoCaptionValidator = [
 ]
 
 const deleteVideoCaptionValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params })
@@ -53,7 +57,7 @@ const deleteVideoCaptionValidator = [
 ]
 
 const listVideoCaptionsValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking listVideoCaptions parameters', { parameters: req.params })
index 1451ab9880a32fdac24d23f7a620a9670aa04ae5..885506ebe691fe21cc9aab718ef3318bb115c8ac 100644 (file)
@@ -3,13 +3,13 @@ import { body, param, query } from 'express-validator'
 import { MUserAccountUrl } from '@server/types/models'
 import { UserRight } from '../../../../shared'
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import { 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 { 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 listVideoCommentsValidator = [
   query('isLocal')
@@ -40,7 +40,7 @@ const listVideoCommentsValidator = [
 ]
 
 const listVideoCommentThreadsValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
@@ -53,8 +53,10 @@ const listVideoCommentThreadsValidator = [
 ]
 
 const listVideoThreadCommentsValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
@@ -68,8 +70,10 @@ const listVideoThreadCommentsValidator = [
 ]
 
 const addVideoCommentThreadValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
@@ -84,8 +88,10 @@ const addVideoCommentThreadValidator = [
 ]
 
 const addVideoCommentReplyValidator = [
 ]
 
 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'),
   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) => {
   body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -102,8 +108,10 @@ const addVideoCommentReplyValidator = [
 ]
 
 const videoCommentGetValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
@@ -117,7 +125,8 @@ const videoCommentGetValidator = [
 ]
 
 const removeVideoCommentValidator = [
 ]
 
 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) => {
   param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
index b058ff5c189a91968c68ea149117c2d06df3073d..7cfb935e306d1c6089c247519a3b64963804e1b4 100644 (file)
@@ -1,5 +1,5 @@
 import * as express from 'express'
 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 { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
 import { isLocalLiveVideoAccepted } from '@server/lib/moderation'
 import { Hooks } from '@server/lib/plugins/hooks'
@@ -7,16 +7,22 @@ import { VideoModel } from '@server/models/video/video'
 import { VideoLiveModel } from '@server/models/video/video-live'
 import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
 import { ServerErrorCode, UserRight, VideoState } from '@shared/models'
 import { 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 { 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 = [
 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 })
 
   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 })
index 120b0469cc92b8c72e007d82139003a164997b8e..54ac46c99cd2c45ef54a059fa386aab485e8e819 100644 (file)
@@ -1,6 +1,6 @@
 import * as express from 'express'
 import { param } from 'express-validator'
 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'
 import { checkUserCanTerminateOwnershipChange } from '@server/helpers/custom-validators/video-ownership'
 import { logger } from '@server/helpers/logger'
 import { isAbleToUploadVideo } from '@server/lib/user'
@@ -13,11 +13,12 @@ import {
   checkUserCanManageVideo,
   doesChangeVideoOwnershipExist,
   doesVideoChannelOfAccountExist,
   checkUserCanManageVideo,
   doesChangeVideoOwnershipExist,
   doesVideoChannelOfAccountExist,
-  doesVideoExist
+  doesVideoExist,
+  isValidVideoIdParam
 } from '../shared'
 
 const videosChangeOwnershipValidator = [
 } 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking changeOwnership parameters', { parameters: req.params })
@@ -40,7 +41,8 @@ const videosChangeOwnershipValidator = [
 ]
 
 const videosTerminateChangeOwnershipValidator = [
 ]
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking changeOwnership parameters', { parameters: req.params })
index 0d2e6e90c5fceacedddccc4c57d2c005aa0fc106..5ee7ee0ce54f561636ac27f7e9f481c3a288afae 100644 (file)
@@ -11,6 +11,7 @@ import {
   isIdOrUUIDValid,
   isIdValid,
   isUUIDValid,
   isIdOrUUIDValid,
   isIdValid,
   isUUIDValid,
+  toCompleteUUID,
   toIntArray,
   toIntOrNull,
   toValueOrNull
   toIntArray,
   toIntOrNull,
   toValueOrNull
@@ -29,7 +30,14 @@ import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
 import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element'
 import { MVideoPlaylist } from '../../../types/models/video/video-playlist'
 import { authenticatePromiseIfNeeded } from '../../auth'
 import { 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 videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
   body('displayName')
@@ -43,10 +51,13 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
     const body: VideoPlaylistCreate = req.body
     if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req)
 
     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)
 
       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()
     }
 
     return next()
@@ -54,8 +65,7 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
 ])
 
 const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
 ])
 
 const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
-  param('playlistId')
-    .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
+  isValidPlaylistIdParam('playlistId'),
 
   body('displayName')
     .optional()
 
   body('displayName')
     .optional()
@@ -101,8 +111,7 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
 ])
 
 const videoPlaylistsDeleteValidator = [
 ])
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking videoPlaylistsDeleteValidator parameters', { parameters: req.params })
@@ -126,8 +135,7 @@ const videoPlaylistsDeleteValidator = [
 
 const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => {
   return [
 
 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 })
 
     async (req: express.Request, res: express.Response, next: express.NextFunction) => {
       logger.debug('Checking videoPlaylistsGetValidator parameters', { parameters: req.params })
@@ -184,9 +192,10 @@ const videoPlaylistsSearchValidator = [
 ]
 
 const videoPlaylistsAddVideoValidator = [
 ]
 
 const videoPlaylistsAddVideoValidator = [
-  param('playlistId')
-    .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
+  isValidPlaylistIdParam('playlistId'),
+
   body('videoId')
   body('videoId')
+    .customSanitizer(toCompleteUUID)
     .custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'),
   body('startTimestamp')
     .optional()
     .custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'),
   body('startTimestamp')
     .optional()
@@ -214,9 +223,9 @@ const videoPlaylistsAddVideoValidator = [
 ]
 
 const videoPlaylistsUpdateOrRemoveVideoValidator = [
 ]
 
 const videoPlaylistsUpdateOrRemoveVideoValidator = [
-  param('playlistId')
-    .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
+  isValidPlaylistIdParam('playlistId'),
   param('playlistElementId')
   param('playlistElementId')
+    .customSanitizer(toCompleteUUID)
     .custom(isIdValid).withMessage('Should have an element id/uuid'),
   body('startTimestamp')
     .optional()
     .custom(isIdValid).withMessage('Should have an element id/uuid'),
   body('startTimestamp')
     .optional()
@@ -251,8 +260,7 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
 ]
 
 const videoPlaylistElementAPGetValidator = [
 ]
 
 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'),
 
   param('playlistElementId')
     .custom(isIdValid).withMessage('Should have an playlist element id'),
 
@@ -287,8 +295,7 @@ const videoPlaylistElementAPGetValidator = [
 ]
 
 const videoPlaylistsReorderVideosValidator = [
 ]
 
 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')
   body('startPosition')
     .isInt({ min: 1 }).withMessage('Should have a valid start position'),
   body('insertAfterPosition')
index 4a802e75ef2fbd9a15eb353ed31ca83834e0cbb8..5d5dfb2227c5b18807d16e99655e9a2e17857f09 100644 (file)
@@ -3,15 +3,16 @@ import { body, param, query } from 'express-validator'
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import { VideoRateType } from '../../../../shared/models/videos'
 import { isAccountNameValid } from '../../../helpers/custom-validators/accounts'
 import { 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 { 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 = [
 
 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) => {
   body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'),
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
index cc2f66e9455775669eb81eb962e69109ba22bbab..7e54b6fc0f6237d6a018083e2e9d2e9d52d3a4d4 100644 (file)
@@ -1,14 +1,16 @@
 import * as express from 'express'
 import { param } from 'express-validator'
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import * 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 { logger } from '../../../helpers/logger'
 import { VideoShareModel } from '../../../models/video/video-share'
-import { areValidationErrors, doesVideoExist } from '../shared'
+import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
 
 const videosShareValidator = [
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking videoShare parameters', { parameters: req.params })
index ef8b89ecece17f51e6d19b00eee49edbc8e58e40..43306f7cda9a39a0dd63c1b52de7dab0d7dc4206 100644 (file)
@@ -1,12 +1,13 @@
 import * as express from 'express'
 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 { 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 { logger } from '../../../helpers/logger'
-import { areValidationErrors, doesVideoExist } from '../shared'
+import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
 
 const videoWatchingValidator = [
 
 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'),
   body('currentTime')
     .customSanitizer(toIntOrNull)
     .isInt().withMessage('Should have correct current time'),
index 8201e80c304a395c22078bda05efde93f8a6f3aa..49e10e2b5497d5751d43664ace446c5208de590f 100644 (file)
@@ -12,7 +12,6 @@ import {
   isBooleanValid,
   isDateValid,
   isFileFieldValid,
   isBooleanValid,
   isDateValid,
   isFileFieldValid,
-  isIdOrUUIDValid,
   isIdValid,
   isUUIDValid,
   toArray,
   isIdValid,
   isUUIDValid,
   toArray,
@@ -53,7 +52,8 @@ import {
   checkUserCanManageVideo,
   doesVideoChannelOfAccountExist,
   doesVideoExist,
   checkUserCanManageVideo,
   doesVideoChannelOfAccountExist,
   doesVideoExist,
-  doesVideoFileOfVideoExist
+  doesVideoFileOfVideoExist,
+  isValidVideoIdParam
 } from '../shared'
 
 const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
 } from '../shared'
 
 const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
@@ -195,7 +195,8 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
 ])
 
 const videosUpdateValidator = getCommonVideoEditAttributes().concat([
 ])
 
 const videosUpdateValidator = getCommonVideoEditAttributes().concat([
-  param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
+  isValidVideoIdParam('id'),
+
   body('name')
     .optional()
     .trim()
   body('name')
     .optional()
     .trim()
@@ -258,7 +259,7 @@ const videosCustomGetValidator = (
   authenticateInQuery = false
 ) => {
   return [
   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 })
 
     async (req: express.Request, res: express.Response, next: express.NextFunction) => {
       logger.debug('Checking videosGet parameters', { parameters: req.params })
@@ -309,8 +310,10 @@ const videosGetValidator = videosCustomGetValidator('all')
 const videosDownloadValidator = videosCustomGetValidator('all', true)
 
 const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params })
@@ -323,7 +326,7 @@ const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
 ])
 
 const videosRemoveValidator = [
 ])
 
 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 })
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking videosRemove parameters', { parameters: req.params })
index 8880c0450f9eecac7813cf1b19b50b5710ffbc46..672c671b89aca03a22941127215ab294bb0ce6a8 100644 (file)
@@ -1,3 +1,4 @@
+import { uuidToShort } from '@server/helpers/uuid'
 import { generateMagnetUri } from '@server/helpers/webtorrent'
 import { getLocalVideoFileMetadataUrl } from '@server/lib/video-paths'
 import { VideoFile } from '@shared/models/videos/video-file.model'
 import { generateMagnetUri } from '@server/helpers/webtorrent'
 import { getLocalVideoFileMetadataUrl } from '@server/lib/video-paths'
 import { VideoFile } from '@shared/models/videos/video-file.model'
@@ -47,6 +48,8 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor
   const videoObject: Video = {
     id: video.id,
     uuid: video.uuid,
   const videoObject: Video = {
     id: video.id,
     uuid: video.uuid,
+    shortUUID: uuidToShort(video.uuid),
+
     name: video.name,
     category: {
       id: video.category,
     name: video.name,
     category: {
       id: video.category,
index 5ec944b9e8042c4bc38a3288451d9953a2318bac..d24be56c3ac8c79a570cfd8797acf791988fc39e 100644 (file)
@@ -15,7 +15,7 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
   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'
 import { MVideo, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models'
 import { AttributesOnly } from '@shared/core-utils'
 import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model'
@@ -182,7 +182,7 @@ export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaption
   }
 
   static generateCaptionName (language: string) {
   }
 
   static generateCaptionName (language: string) {
-    return `${uuidv4()}-${language}.vtt`
+    return `${buildUUID()}-${language}.vtt`
   }
 
   isOwned () {
   }
 
   isOwned () {
index 7aa6b6c6e18bb77bd3e17156d1f14255928b61b7..af81c9906808f24e8b1b17ce9354e057d1a317e0 100644 (file)
@@ -17,8 +17,8 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
-import { v4 as uuidv4 } from 'uuid'
 import { setAsUpdated } from '@server/helpers/database-utils'
 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'
 import { MAccountId, MChannelId } from '@server/types/models'
 import { AttributesOnly } from '@shared/core-utils'
 import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
@@ -545,7 +545,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
   generateThumbnailName () {
     const extension = '.jpg'
 
   generateThumbnailName () {
     const extension = '.jpg'
 
-    return 'playlist-' + uuidv4() + extension
+    return 'playlist-' + buildUUID() + extension
   }
 
   getThumbnailUrl () {
   }
 
   getThumbnailUrl () {
@@ -617,6 +617,8 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
     return {
       id: this.id,
       uuid: this.uuid,
     return {
       id: this.id,
       uuid: this.uuid,
+      shortUUID: uuidToShort(this.uuid),
+
       isLocal: this.isOwned(),
 
       url: this.url,
       isLocal: this.isOwned(),
 
       url: this.url,
index b6c538e19781a2f1cd445f1cf8cb40056f1ed1cd..be94e219c5e9738a6cab89d4d402594f916746c6 100644 (file)
@@ -1,23 +1,65 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
-import * as chai from 'chai'
 import 'mocha'
 import 'mocha'
+import * as chai from 'chai'
+import { VideoPlaylistPrivacy } from '@shared/models'
+import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   cleanupTests,
 import {
   cleanupTests,
+  createVideoPlaylist,
   doubleFollow,
   flushAndRunMultipleServers,
   makeActivityPubGetRequest,
   ServerInfo,
   setAccessTokensToServers,
   doubleFollow,
   flushAndRunMultipleServers,
   makeActivityPubGetRequest,
   ServerInfo,
   setAccessTokensToServers,
-  uploadVideo
+  setDefaultVideoChannel,
+  uploadVideoAndGetId
 } from '../../../../shared/extra-utils'
 } 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[] = []
 
 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)
 
   before(async function () {
     this.timeout(30000)
@@ -25,38 +67,56 @@ describe('Test activitypub', function () {
     servers = await flushAndRunMultipleServers(2)
 
     await setAccessTokensToServers(servers)
     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 () {
     }
 
     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 () {
   })
 
   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 () {
   })
 
   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 () {
   })
 
   after(async function () {
index 2aa09334c8bedd6ed3edad45f56803efa0e244da..2054776cc62c9921d6952982442fdcc791b6b50e 100644 (file)
@@ -258,7 +258,7 @@ describe('Test abuses API validators', function () {
     })
 
     it('Should succeed with the correct parameters (basic)', 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,
 
       const res = await makePostBodyRequest({
         url: server.url,
index 32233c9da79357980a91bb79054a95f1dd663092..933d8abf2c615c5b889d3ace38582d78a50c6018 100644 (file)
@@ -2,7 +2,7 @@
 
 import 'mocha'
 import { omit } from 'lodash'
 
 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,
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   buildAbsoluteFixturePath,
@@ -31,7 +31,7 @@ describe('Test video lives API validator', function () {
   let server: ServerInfo
   let userAccessToken = ''
   let channelId: number
   let server: ServerInfo
   let userAccessToken = ''
   let channelId: number
-  let videoId: number
+  let video: VideoCreateResult
   let videoIdNotLive: number
 
   // ---------------------------------------------------------------
   let videoIdNotLive: number
 
   // ---------------------------------------------------------------
@@ -230,7 +230,7 @@ describe('Test video lives API validator', function () {
         statusCodeExpected: HttpStatusCode.OK_200
       })
 
         statusCodeExpected: HttpStatusCode.OK_200
       })
 
-      videoId = res.body.video.id
+      video = res.body.video
     })
 
     it('Should forbid if live is disabled', async function () {
     })
 
     it('Should forbid if live is disabled', async function () {
@@ -326,15 +326,15 @@ describe('Test video lives API validator', function () {
   describe('When getting live information', function () {
 
     it('Should fail without access token', async function () {
   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 () {
     })
 
     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 () {
     })
 
     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 fail with a bad video id', async function () {
@@ -350,22 +350,23 @@ describe('Test video lives API validator', function () {
     })
 
     it('Should succeed with the correct params', async function () {
     })
 
     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 () {
     })
   })
 
   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 () {
     })
 
     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 () {
     })
 
     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 a bad video id', async function () {
@@ -383,11 +384,12 @@ describe('Test video lives API validator', function () {
     it('Should fail with save replay and permanent live set to true', async function () {
       const fields = { saveReplay: true, permanentLive: true }
 
     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 () {
     })
 
     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 () {
     })
 
     it('Should fail to update replay status if replay is not allowed on the instance', async function () {
@@ -398,19 +400,19 @@ describe('Test video lives API validator', function () {
         }
       })
 
         }
       })
 
-      await updateLive(server.url, server.accessToken, videoId, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403)
+      await updateLive(server.url, server.accessToken, video.id, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403)
     })
 
     it('Should fail to update a live if it has already started', async function () {
       this.timeout(40000)
 
     })
 
     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)
 
       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)
     })
 
       await stopFfmpeg(command)
     })
@@ -418,14 +420,14 @@ describe('Test video lives API validator', function () {
     it('Should fail to stream twice in the save live', async function () {
       this.timeout(40000)
 
     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)
 
       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)
     })
 
       await stopFfmpeg(command)
     })
index 71be50a6f20bd9a114e626ff75ab6810e743bafa..dac6938de1296c90227ed995c9637c995ccd22f0 100644 (file)
@@ -1,7 +1,8 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 import 'mocha'
 /* 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,
 import {
   checkBadCountPagination,
   checkBadSortPagination,
@@ -9,20 +10,24 @@ import {
   cleanupTests,
   createUser,
   doubleFollow,
   cleanupTests,
   createUser,
   doubleFollow,
-  flushAndRunMultipleServers, makeDeleteRequest,
-  makeGetRequest, makePostBodyRequest,
+  flushAndRunMultipleServers,
+  getVideo,
+  makeDeleteRequest,
+  makeGetRequest,
+  makePostBodyRequest,
   makePutBodyRequest,
   ServerInfo,
   makePutBodyRequest,
   ServerInfo,
-  setAccessTokensToServers, uploadVideoAndGetId,
-  userLogin, waitJobs, getVideoIdFromUUID
+  setAccessTokensToServers,
+  uploadVideoAndGetId,
+  userLogin,
+  waitJobs
 } from '../../../../shared/extra-utils'
 } 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
 
 describe('Test server redundancy API validators', function () {
   let servers: ServerInfo[]
   let userAccessToken = null
   let videoIdLocal: number
-  let videoIdRemote: number
+  let videoRemote: VideoCreateResult
 
   // ---------------------------------------------------------------
 
 
   // ---------------------------------------------------------------
 
@@ -48,7 +53,8 @@ describe('Test server redundancy API validators', function () {
 
     await waitJobs(servers)
 
 
     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 () {
   })
 
   describe('When listing redundancies', function () {
@@ -131,7 +137,13 @@ describe('Test server redundancy API validators', function () {
     })
 
     it('Should succeed with the correct params', async function () {
     })
 
     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 () {
     })
 
     it('Should fail if the video is already duplicated', async function () {
@@ -139,7 +151,13 @@ describe('Test server redundancy API validators', function () {
 
       await waitJobs(servers)
 
 
       await 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
+      })
     })
   })
 
     })
   })
 
index 36482ee17a80232d9c5eb00bab278e6d10e9c783..70a872ce57f17ac9a92bbf322959f26a8d3edf72 100644 (file)
@@ -2,7 +2,7 @@
 
 import 'mocha'
 import { omit } from 'lodash'
 
 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,
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   addVideoChannel,
@@ -45,7 +45,7 @@ describe('Test users API validators', function () {
   let userId: number
   let rootId: number
   let moderatorId: number
   let userId: number
   let rootId: number
   let moderatorId: number
-  let videoId: number
+  let video: VideoCreateResult
   let server: ServerInfo
   let serverWithRegistrationDisabled: ServerInfo
   let userAccessToken = ''
   let server: ServerInfo
   let serverWithRegistrationDisabled: ServerInfo
   let userAccessToken = ''
@@ -126,7 +126,7 @@ describe('Test users API validators', function () {
 
     {
       const res = await uploadVideo(server.url, server.accessToken, {})
 
     {
       const res = await uploadVideo(server.url, server.accessToken, {})
-      videoId = res.body.video.id
+      video = res.body.video
     }
 
     {
     }
 
     {
@@ -829,7 +829,7 @@ describe('Test users API validators', function () {
 
   describe('When getting my video rating', function () {
     it('Should fail with a non authenticated user', async function () {
 
   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 fail with an incorrect video uuid', async function () {
@@ -841,7 +841,9 @@ describe('Test users API validators', function () {
     })
 
     it('Should succeed with the correct parameters', async function () {
     })
 
     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)
     })
   })
 
     })
   })
 
index 3d4837d58e294a7993f8ff61c8045875c3ab2d69..ce7f5fa17816327f25e06d2da0a3e0cd70866e47 100644 (file)
@@ -191,7 +191,7 @@ describe('Test video blacklist API validators', function () {
     })
 
     it('Should succeed with the correct params', async function () {
     })
 
     it('Should succeed with the correct params', async function () {
-      const path = basePath + servers[0].video.uuid + '/blacklist'
+      const path = basePath + servers[0].video.shortUUID + '/blacklist'
       const fields = { reason: 'hello' }
 
       await makePutBodyRequest({
       const fields = { reason: 'hello' }
 
       await makePutBodyRequest({
@@ -222,10 +222,14 @@ describe('Test video blacklist API validators', function () {
     })
 
     it('Should succeed with an admin', async function () {
     })
 
     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
+      }
     })
   })
 
     })
   })
 
index 1ce2202d2a63c2c1d381a24af6cc9c48ab8d4de3..c0595c04d87a78e7a98d7c0e74ceec2e7af0ef87 100644 (file)
@@ -1,7 +1,7 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 import 'mocha'
 /* 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,
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   buildAbsoluteFixturePath,
@@ -23,7 +23,7 @@ describe('Test video captions API validator', function () {
 
   let server: ServerInfo
   let userAccessToken: string
 
   let server: ServerInfo
   let userAccessToken: string
-  let videoUUID: string
+  let video: VideoCreateResult
 
   // ---------------------------------------------------------------
 
 
   // ---------------------------------------------------------------
 
@@ -36,7 +36,7 @@ describe('Test video captions API validator', function () {
 
     {
       const res = await uploadVideo(server.url, server.accessToken, {})
 
     {
       const res = await uploadVideo(server.url, server.accessToken, {})
-      videoUUID = res.body.video.uuid
+      video = res.body.video
     }
 
     {
     }
 
     {
@@ -79,7 +79,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should fail with a missing language in path', async function () {
     })
 
     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,
       await makeUploadRequest({
         method: 'PUT',
         url: server.url,
@@ -91,7 +91,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should fail with an unknown language', async function () {
     })
 
     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,
       await makeUploadRequest({
         method: 'PUT',
         url: server.url,
@@ -103,7 +103,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should fail without access token', async function () {
     })
 
     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,
       await makeUploadRequest({
         method: 'PUT',
         url: server.url,
@@ -115,7 +115,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should fail with a bad access token', async function () {
     })
 
     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,
       await makeUploadRequest({
         method: 'PUT',
         url: server.url,
@@ -133,7 +133,7 @@ describe('Test video captions API validator', function () {
     //     'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt')
     //   }
     //
     //     '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,
     //   await makeUploadRequest({
     //     method: 'PUT',
     //     url: server.url,
@@ -151,7 +151,7 @@ describe('Test video captions API validator', function () {
     //     url: server.url,
     //     accessToken: server.accessToken,
     //     language: 'zh',
     //     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
     //     fixture: 'subtitle-bad.txt',
     //     mimeType: 'application/octet-stream',
     //     statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
@@ -163,7 +163,7 @@ describe('Test video captions API validator', function () {
         url: server.url,
         accessToken: server.accessToken,
         language: 'zh',
         url: server.url,
         accessToken: server.accessToken,
         language: 'zh',
-        videoId: videoUUID,
+        videoId: video.uuid,
         fixture: 'subtitle-good.srt',
         mimeType: 'application/octet-stream'
       })
         fixture: 'subtitle-good.srt',
         mimeType: 'application/octet-stream'
       })
@@ -175,7 +175,7 @@ describe('Test video captions API validator', function () {
     //     'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt')
     //   }
     //
     //     '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,
     //   await makeUploadRequest({
     //     method: 'PUT',
     //     url: server.url,
@@ -188,7 +188,7 @@ describe('Test video captions API validator', function () {
     // })
 
     it('Should success with the correct parameters', async function () {
     // })
 
     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,
       await makeUploadRequest({
         method: 'PUT',
         url: server.url,
@@ -215,7 +215,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should success with the correct parameters', async function () {
     })
 
     it('Should success with the correct parameters', async function () {
-      await makeGetRequest({ url: server.url, path: path + videoUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 })
+      await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 })
     })
   })
 
     })
   })
 
@@ -246,27 +246,27 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should fail with a missing language', async function () {
     })
 
     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 () {
       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 () {
       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 () {
       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 () {
       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,
       await makeDeleteRequest({
         url: server.url,
         path: captionPath,
@@ -276,7 +276,7 @@ describe('Test video captions API validator', function () {
     })
 
     it('Should success with the correct parameters', async function () {
     })
 
     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,
       await makeDeleteRequest({
         url: server.url,
         path: captionPath,
index 659a10c413bd614f92a72bd058e6c019cc03bf5f..a38420851f8d109b394898a7ad9539755b69a1c4 100644 (file)
@@ -1,7 +1,9 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
-import * as chai from 'chai'
 import 'mocha'
 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,
 import {
   cleanupTests,
   createUser,
@@ -20,7 +22,6 @@ import {
   checkBadStartPagination
 } from '../../../../shared/extra-utils/requests/check-api-params'
 import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
   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
 
 
 const expect = chai.expect
 
@@ -28,7 +29,7 @@ describe('Test video comments API validator', function () {
   let pathThread: string
   let pathComment: string
   let server: ServerInfo
   let pathThread: string
   let pathComment: string
   let server: ServerInfo
-  let videoUUID: string
+  let video: VideoCreateResult
   let userAccessToken: string
   let userAccessToken2: string
   let commentId: number
   let userAccessToken: string
   let userAccessToken2: string
   let commentId: number
@@ -44,14 +45,14 @@ describe('Test video comments API validator', function () {
 
     {
       const res = await uploadVideo(server.url, server.accessToken, {})
 
     {
       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
       commentId = res.body.comment.id
-      pathComment = '/api/v1/videos/' + videoUUID + '/comments/' + commentId
+      pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId
     }
 
     {
     }
 
     {
@@ -101,7 +102,7 @@ describe('Test video comments API validator', function () {
     it('Should fail with an incorrect thread id', async function () {
       await makeGetRequest({
         url: server.url,
     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
       })
     })
         statusCodeExpected: HttpStatusCode.NOT_FOUND_404
       })
     })
@@ -109,7 +110,7 @@ describe('Test video comments API validator', function () {
     it('Should success with the correct params', async function () {
       await makeGetRequest({
         url: server.url,
     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
       })
     })
         statusCodeExpected: HttpStatusCode.OK_200
       })
     })
@@ -225,7 +226,7 @@ describe('Test video comments API validator', function () {
     })
 
     it('Should fail with an incorrect comment', async function () {
     })
 
     it('Should fail with an incorrect comment', async function () {
-      const path = '/api/v1/videos/' + videoUUID + '/comments/124'
+      const path = '/api/v1/videos/' + video.uuid + '/comments/124'
       const fields = {
         text: 'super comment'
       }
       const fields = {
         text: 'super comment'
       }
@@ -272,7 +273,7 @@ describe('Test video comments API validator', function () {
     })
 
     it('Should fail with an incorrect comment', async function () {
     })
 
     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 })
     })
 
       await makeDeleteRequest({ url: server.url, path, token: server.accessToken, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
     })
 
@@ -280,11 +281,11 @@ describe('Test video comments API validator', function () {
       let commentToDelete: number
 
       {
       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
       }
 
         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 })
 
       await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
       await makeDeleteRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 })
@@ -323,8 +324,8 @@ describe('Test video comments API validator', function () {
   describe('When a video has comments disabled', function () {
     before(async function () {
       const res = await uploadVideo(server.url, server.accessToken, { commentsEnabled: false })
   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 () {
     })
 
     it('Should return an empty thread list', async function () {
index bbea88354cca0d9baa0204ba3a2ee8c9cc38049b..18253d11aef3e8deeffac14a179e7221e72a12df 100644 (file)
@@ -1,8 +1,13 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 import 'mocha'
 /* 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,
 import {
   addVideoInPlaylist,
+  checkBadCountPagination,
+  checkBadSortPagination,
+  checkBadStartPagination,
   cleanupTests,
   createVideoPlaylist,
   deleteVideoPlaylist,
   cleanupTests,
   createVideoPlaylist,
   deleteVideoPlaylist,
@@ -21,20 +26,14 @@ import {
   updateVideoPlaylistElement,
   uploadVideoAndGetId
 } from '../../../../shared/extra-utils'
   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
 
 describe('Test video playlists API validator', function () {
   let server: ServerInfo
   let userAccessToken: string
-  let playlistUUID: string
+
+  let playlist: VideoPlaylistCreateResult
   let privatePlaylistUUID: string
   let privatePlaylistUUID: string
+
   let watchLaterPlaylistId: number
   let videoId: number
   let playlistElementId: number
   let watchLaterPlaylistId: number
   let videoId: number
   let playlistElementId: number
@@ -67,7 +66,7 @@ describe('Test video playlists API validator', function () {
           videoChannelId: server.videoChannel.id
         }
       })
           videoChannelId: server.videoChannel.id
         }
       })
-      playlistUUID = res.body.videoPlaylist.uuid
+      playlist = res.body.videoPlaylist
     }
 
     {
     }
 
     {
@@ -150,15 +149,15 @@ describe('Test video playlists API validator', function () {
     const path = '/api/v1/video-playlists/'
 
     it('Should fail with a bad start pagination', async function () {
     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 () {
     })
 
     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 () {
     })
 
     it('Should success with the correct parameters', async function () {
-      await makeGetRequest({ url: server.url, path: path + playlistUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
+      await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
     })
   })
 
     })
   })
 
@@ -177,6 +176,7 @@ describe('Test video playlists API validator', function () {
         token: server.accessToken,
         playlistAttrs: {
           displayName: 'super playlist',
         token: server.accessToken,
         playlistAttrs: {
           displayName: 'super playlist',
+          videoChannelId: server.videoChannel.id,
           privacy: VideoPlaylistPrivacy.UNLISTED
         }
       })
           privacy: VideoPlaylistPrivacy.UNLISTED
         }
       })
@@ -187,7 +187,7 @@ describe('Test video playlists API validator', function () {
     })
 
     it('Should succeed with the correct params', async function () {
     })
 
     it('Should succeed with the correct params', async function () {
-      await getVideoPlaylist(server.url, playlistUUID, HttpStatusCode.OK_200)
+      await getVideoPlaylist(server.url, playlist.uuid, HttpStatusCode.OK_200)
     })
   })
 
     })
   })
 
@@ -213,7 +213,7 @@ describe('Test video playlists API validator', function () {
       const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
 
       await createVideoPlaylist(params)
       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 () {
     })
 
     it('Should fail without displayName', async function () {
@@ -226,42 +226,42 @@ describe('Test video playlists API validator', function () {
       const params = getBase({ displayName: 's'.repeat(300) })
 
       await createVideoPlaylist(params)
       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)
     })
 
     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)
     })
 
     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)
     })
 
     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)
     })
 
     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)
     })
 
     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 () {
     })
 
     it('Should fail to set "public" a playlist not assigned to a channel', async function () {
@@ -272,8 +272,8 @@ describe('Test video playlists API validator', function () {
       await createVideoPlaylist(params)
       await createVideoPlaylist(params2)
       await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID))
       await 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 with an unknown playlist to update', async function () {
@@ -286,7 +286,7 @@ describe('Test video playlists API validator', function () {
     it('Should fail to update a playlist of another user', async function () {
       await updateVideoPlaylist(getUpdate(
         getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
     it('Should fail to update a playlist of another user', async function () {
       await updateVideoPlaylist(getUpdate(
         getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
-        playlistUUID
+        playlist.shortUUID
       ))
     })
 
       ))
     })
 
@@ -305,7 +305,7 @@ describe('Test video playlists API validator', function () {
 
       {
         const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
 
       {
         const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
-        await updateVideoPlaylist(getUpdate(params, playlistUUID))
+        await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
       }
     })
   })
       }
     })
   })
@@ -316,7 +316,7 @@ describe('Test video playlists API validator', function () {
         expectedStatus: HttpStatusCode.BAD_REQUEST_400,
         url: server.url,
         token: server.accessToken,
         expectedStatus: HttpStatusCode.BAD_REQUEST_400,
         url: server.url,
         token: server.accessToken,
-        playlistId: playlistUUID,
+        playlistId: playlist.id,
         elementAttrs: Object.assign({
           videoId,
           startTimestamp: 2,
         elementAttrs: Object.assign({
           videoId,
           startTimestamp: 2,
@@ -381,7 +381,7 @@ describe('Test video playlists API validator', function () {
           stopTimestamp: 2
         }, elementAttrs),
         playlistElementId,
           stopTimestamp: 2
         }, elementAttrs),
         playlistElementId,
-        playlistId: playlistUUID,
+        playlistId: playlist.id,
         expectedStatus: HttpStatusCode.BAD_REQUEST_400
       }, wrapper)
     }
         expectedStatus: HttpStatusCode.BAD_REQUEST_400
       }, wrapper)
     }
@@ -451,7 +451,7 @@ describe('Test video playlists API validator', function () {
       return Object.assign({
         url: server.url,
         token: server.accessToken,
       return Object.assign({
         url: server.url,
         token: server.accessToken,
-        playlistId: playlistUUID,
+        playlistId: playlist.shortUUID,
         elementAttrs: Object.assign({
           startPosition: 1,
           insertAfterPosition: 2,
         elementAttrs: Object.assign({
           startPosition: 1,
           insertAfterPosition: 2,
@@ -469,7 +469,7 @@ describe('Test video playlists API validator', function () {
         await addVideoInPlaylist({
           url: server.url,
           token: server.accessToken,
         await addVideoInPlaylist({
           url: server.url,
           token: server.accessToken,
-          playlistId: playlistUUID,
+          playlistId: playlist.shortUUID,
           elementAttrs: { videoId: id }
         })
       }
           elementAttrs: { videoId: id }
         })
       }
@@ -606,7 +606,7 @@ describe('Test video playlists API validator', function () {
         url: server.url,
         token: server.accessToken,
         playlistElementId,
         url: server.url,
         token: server.accessToken,
         playlistElementId,
-        playlistId: playlistUUID,
+        playlistId: playlist.uuid,
         expectedStatus: HttpStatusCode.BAD_REQUEST_400
       }, wrapper)
     }
         expectedStatus: HttpStatusCode.BAD_REQUEST_400
       }, wrapper)
     }
@@ -662,7 +662,7 @@ describe('Test video playlists API validator', function () {
     })
 
     it('Should fail with a playlist of another user', async function () {
     })
 
     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 fail with the watch later playlist', async function () {
@@ -670,7 +670,7 @@ describe('Test video playlists API validator', function () {
     })
 
     it('Should succeed with the correct params', async function () {
     })
 
     it('Should succeed with the correct params', async function () {
-      await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID)
+      await deleteVideoPlaylist(server.url, server.accessToken, playlist.uuid)
     })
   })
 
     })
   })
 
index a6eecb13ae013c39820b32849961833dcd9baab0..4d7a9a23bbd7ac6e22020dffb9dbe92fa3a561c2 100644 (file)
@@ -5,7 +5,7 @@ import * as chai from 'chai'
 import { omit } from 'lodash'
 import { join } from 'path'
 import { randomInt } from '@shared/core-utils'
 import { 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,
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   checkUploadVideoParam,
@@ -42,7 +42,7 @@ describe('Test videos API validator', function () {
   let accountName: string
   let channelId: number
   let channelName: string
   let accountName: string
   let channelId: number
   let channelName: string
-  let videoId
+  let video: VideoCreateResult
 
   // ---------------------------------------------------------------
 
 
   // ---------------------------------------------------------------
 
@@ -490,7 +490,7 @@ describe('Test videos API validator', function () {
 
     before(async function () {
       const res = await getVideosList(server.url)
 
     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 nothing', async function () {
@@ -518,79 +518,79 @@ describe('Test videos API validator', function () {
     it('Should fail with a long name', async function () {
       const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
 
     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 })
 
     })
 
     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 })
 
     })
 
     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) })
 
     })
 
     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) })
 
     })
 
     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) })
 
     })
 
     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 })
 
     })
 
     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' ] })
 
     })
 
     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' ] })
 
     })
 
     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' ] })
 
     })
 
     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 } })
 
     })
 
     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 } })
 
     })
 
     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' })
 
     })
 
     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 () {
     })
 
     it('Should fail with an incorrect thumbnail file', async function () {
@@ -602,7 +602,7 @@ describe('Test videos API validator', function () {
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: server.accessToken,
         fields,
         attaches
         token: server.accessToken,
         fields,
         attaches
@@ -618,7 +618,7 @@ describe('Test videos API validator', function () {
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: server.accessToken,
         fields,
         attaches
         token: server.accessToken,
         fields,
         attaches
@@ -634,7 +634,7 @@ describe('Test videos API validator', function () {
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: server.accessToken,
         fields,
         attaches
         token: server.accessToken,
         fields,
         attaches
@@ -650,7 +650,7 @@ describe('Test videos API validator', function () {
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
       await makeUploadRequest({
         url: server.url,
         method: 'PUT',
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: server.accessToken,
         fields,
         attaches
         token: server.accessToken,
         fields,
         attaches
@@ -662,7 +662,7 @@ describe('Test videos API validator', function () {
 
       await makePutBodyRequest({
         url: server.url,
 
       await makePutBodyRequest({
         url: server.url,
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: userAccessToken,
         fields,
         statusCodeExpected: HttpStatusCode.FORBIDDEN_403
         token: userAccessToken,
         fields,
         statusCodeExpected: HttpStatusCode.FORBIDDEN_403
@@ -674,7 +674,7 @@ describe('Test videos API validator', function () {
     it('Shoud report the appropriate error', async function () {
       const fields = immutableAssign(baseCorrectParams, { licence: 125 })
 
     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')
       const error = res.body as PeerTubeProblemDocument
 
       expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo')
@@ -694,7 +694,7 @@ describe('Test videos API validator', function () {
 
       await makePutBodyRequest({
         url: server.url,
 
       await makePutBodyRequest({
         url: server.url,
-        path: path + videoId,
+        path: path + video.shortUUID,
         token: server.accessToken,
         fields,
         statusCodeExpected: HttpStatusCode.NO_CONTENT_204
         token: server.accessToken,
         fields,
         statusCodeExpected: HttpStatusCode.NO_CONTENT_204
@@ -739,7 +739,7 @@ describe('Test videos API validator', function () {
     })
 
     it('Should succeed with the correct parameters', async function () {
     })
 
     it('Should succeed with the correct parameters', async function () {
-      await getVideo(server.url, videoId)
+      await getVideo(server.url, video.shortUUID)
     })
   })
 
     })
   })
 
@@ -810,7 +810,7 @@ describe('Test videos API validator', function () {
     })
 
     it('Should fail with a video of another user without the appropriate right', async function () {
     })
 
     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 fail with a video of another server')
@@ -832,7 +832,7 @@ describe('Test videos API validator', function () {
     })
 
     it('Should succeed with the correct parameters', async function () {
     })
 
     it('Should succeed with the correct parameters', async function () {
-      await removeVideo(server.url, server.accessToken, videoId)
+      await removeVideo(server.url, server.accessToken, video.uuid)
     })
   })
 
     })
   })
 
index 4ce6675b6f05dea2a7fec041b6ddfb464b10ae81..3425480aeb314d1c0362c9b10b06edb963c18b87 100644 (file)
@@ -1,7 +1,7 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 import 'mocha'
 /* 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,
 import { AbuseState } from '@shared/models'
 import {
   addAbuseMessage,
@@ -85,7 +85,7 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to moderators on local video abuse', async function () {
       this.timeout(20000)
 
     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
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const video = resVideo.body.video
 
@@ -98,7 +98,7 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to moderators on remote video abuse', async function () {
       this.timeout(20000)
 
     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
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const video = resVideo.body.video
 
@@ -114,10 +114,10 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to moderators on local comment abuse', async function () {
       this.timeout(20000)
 
     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 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)
       const comment = resComment.body.comment
 
       await waitJobs(servers)
@@ -131,10 +131,10 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to moderators on remote comment abuse', async function () {
       this.timeout(20000)
 
     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
       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)
 
 
       await waitJobs(servers)
 
@@ -188,7 +188,7 @@ describe('Test moderation notifications', function () {
         token: userAccessToken
       }
 
         token: userAccessToken
       }
 
-      const name = 'abuse ' + uuidv4()
+      const name = 'abuse ' + buildUUID()
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const video = resVideo.body.video
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const video = resVideo.body.video
 
@@ -236,7 +236,7 @@ describe('Test moderation notifications', function () {
         token: servers[0].accessToken
       }
 
         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
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const video = resVideo.body.video
 
@@ -307,7 +307,7 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to video owner on blacklist', async function () {
       this.timeout(10000)
 
     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
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const uuid = resVideo.body.video.uuid
 
@@ -320,7 +320,7 @@ describe('Test moderation notifications', function () {
     it('Should send a notification to video owner on unblacklist', async function () {
       this.timeout(10000)
 
     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
 
       const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
       const uuid = resVideo.body.video.uuid
 
@@ -507,7 +507,7 @@ describe('Test moderation notifications', function () {
     it('Should send notification to moderators on new video with auto-blacklist', async function () {
       this.timeout(40000)
 
     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 resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName })
       videoUUID = resVideo.body.video.uuid
 
@@ -553,7 +553,7 @@ describe('Test moderation notifications', function () {
 
       const updateAt = new Date(new Date().getTime() + 1000000)
 
 
       const 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,
 
       const data = {
         name,
@@ -586,7 +586,7 @@ describe('Test moderation notifications', function () {
       // In 2 seconds
       const updateAt = new Date(new Date().getTime() + 2000)
 
       // 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,
 
       const data = {
         name,
@@ -609,7 +609,7 @@ describe('Test moderation notifications', function () {
     it('Should not send a notification to moderators on new video without auto-blacklist', async function () {
       this.timeout(60000)
 
     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 })
 
       // admin with blacklist right will not be auto-blacklisted
       const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name })
index 7e88d979b89bc527eaf9ab6a45add874c5e3becb..e981c17189a672cd861db68652138e9e962e0343 100644 (file)
@@ -2,7 +2,7 @@
 
 import 'mocha'
 import * as chai from 'chai'
 
 import 'mocha'
 import * as chai from 'chai'
-import { v4 as uuidv4 } from 'uuid'
+import { buildUUID } from '@server/helpers/uuid'
 import {
   cleanupTests,
   updateMyUser,
 import {
   cleanupTests,
   updateMyUser,
@@ -207,7 +207,7 @@ describe('Test user notifications', function () {
     it('Should send a new video notification after a video import', async function () {
       this.timeout(100000)
 
     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,
 
       const attributes = {
         name,
@@ -278,7 +278,7 @@ describe('Test user notifications', function () {
     it('Should send a notification when an imported video is transcoded', async function () {
       this.timeout(50000)
 
     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,
 
       const attributes = {
         name,
@@ -347,7 +347,7 @@ describe('Test user notifications', function () {
     it('Should send a notification when the video import failed', async function () {
       this.timeout(70000)
 
     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,
 
       const attributes = {
         name,
@@ -365,7 +365,7 @@ describe('Test user notifications', function () {
     it('Should send a notification when the video import succeeded', async function () {
       this.timeout(70000)
 
     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,
 
       const attributes = {
         name,
index fe4a0e100eff3e39902f3b6f547a8c5c0ffe45f7..d57d72f5e4763ee50516df698b1ef759f8286f0d 100644 (file)
@@ -47,7 +47,7 @@ describe('Test handle downs', function () {
   let missedVideo2: Video
   let unlistedVideo: Video
 
   let missedVideo2: Video
   let unlistedVideo: Video
 
-  const videoIdsServer1: number[] = []
+  const videoIdsServer1: string[] = []
 
   const videoAttributes = {
     name: 'my super name for server 1',
 
   const videoAttributes = {
     name: 'my super name for server 1',
index 9dad58c8cc9626560e49647515e5768efdc77842..da8de054b612dae26e971d3174731ef8e894dba2 100644 (file)
@@ -56,7 +56,7 @@ import {
   removeServerFromServerBlocklist
 } from '../../../../shared/extra-utils/users/blocklist'
 import { User } from '../../../../shared/models/users'
   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'
 import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
 import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
@@ -427,31 +427,45 @@ describe('Test video playlists', function () {
         expect(data).to.have.lengthOf(0)
       }
     })
         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)
 
       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)
 
       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'),
       for (const server of servers) {
         const results = [
           await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
@@ -469,6 +483,27 @@ describe('Test video playlists', function () {
         }
       }
     })
         }
       }
     })
+
+    it('Should not get unlisted playlist using only the id', async function () {
+      await getVideoPlaylist(servers[1].url, unlistedPlaylist.id, 404)
+    })
+
+    it('Should get unlisted plyaylist using uuid or shortUUID', async function () {
+      await getVideoPlaylist(servers[1].url, unlistedPlaylist.uuid)
+      await getVideoPlaylist(servers[1].url, unlistedPlaylist.shortUUID)
+    })
+
+    it('Should not get private playlist without token', async function () {
+      for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
+        await getVideoPlaylist(servers[1].url, id, 401)
+      }
+    })
+
+    it('Should get private playlist with a token', async function () {
+      for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
+        await getVideoPlaylistWithToken(servers[1].url, servers[1].accessToken, id)
+      }
+    })
   })
 
   describe('Update playlists', function () {
   })
 
   describe('Update playlists', function () {
index fed6ca0e0ac9e1b848a401ed63cfd19419592135..950aeb7cf713a223c0349c9c68f3661cf0c8b5c7 100644 (file)
@@ -1,8 +1,9 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
-import * as chai from 'chai'
 import 'mocha'
 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,
 import {
   cleanupTests,
   flushAndRunServer,
@@ -13,12 +14,11 @@ import {
   uploadVideo
 } from '../../../../shared/extra-utils/index'
 import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
   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 { 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
 
 
 const expect = chai.expect
 
@@ -32,7 +32,7 @@ describe('Test video privacy', function () {
   let internalVideoId: number
   let internalVideoUUID: string
 
   let internalVideoId: number
   let internalVideoUUID: string
 
-  let unlistedVideoUUID: string
+  let unlistedVideo: VideoCreateResult
   let nonFederatedUnlistedVideoUUID: string
 
   let now: number
   let nonFederatedUnlistedVideoUUID: string
 
   let now: number
@@ -59,231 +59,246 @@ describe('Test video privacy', function () {
     await doubleFollow(servers[0], servers[1])
   })
 
     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 () {
   })
 
   after(async function () {
index 5c9e023e1e23723f46207294ddbea9c27d473fb9..a0af09de8d7788ae774bb8b0a4de6f4d5ec82b3c 100644 (file)
@@ -2,7 +2,10 @@
 
 import 'mocha'
 import * as chai from 'chai'
 
 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,
 import {
   buildServerDirectory,
   cleanupTests,
@@ -21,11 +24,8 @@ import {
   uploadVideo,
   wait
 } from '../../../shared/extra-utils'
   uploadVideo,
   wait
 } from '../../../shared/extra-utils'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
 import { Account, VideoPlaylistPrivacy } from '../../../shared/models'
 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 expect = chai.expect
 
@@ -131,8 +131,8 @@ describe('Test prune storage scripts', function () {
       {
         const base = buildServerDirectory(servers[0], 'videos')
 
       {
         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))
 
         await createFile(join(base, n1))
         await createFile(join(base, n2))
@@ -143,8 +143,8 @@ describe('Test prune storage scripts', function () {
       {
         const base = buildServerDirectory(servers[0], 'torrents')
 
       {
         const 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))
 
         await createFile(join(base, n1))
         await createFile(join(base, n2))
@@ -155,8 +155,8 @@ describe('Test prune storage scripts', function () {
       {
         const base = buildServerDirectory(servers[0], 'thumbnails')
 
       {
         const 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))
 
         await createFile(join(base, n1))
         await createFile(join(base, n2))
@@ -167,8 +167,8 @@ describe('Test prune storage scripts', function () {
       {
         const base = buildServerDirectory(servers[0], 'previews')
 
       {
         const 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))
 
         await createFile(join(base, n1))
         await createFile(join(base, n2))
@@ -179,8 +179,8 @@ describe('Test prune storage scripts', function () {
       {
         const base = buildServerDirectory(servers[0], 'avatars')
 
       {
         const 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))
 
         await createFile(join(base, n1))
         await createFile(join(base, n2))
index 253a9562432a75e047839f0997caf03cf23dd3ba..7c4fb4e46c0976d66c382015dea09ddb8886305e 100644 (file)
@@ -3,9 +3,8 @@
 import 'mocha'
 import * as chai from 'chai'
 import { omit } from 'lodash'
 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 { 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,
 import {
   addVideoInPlaylist,
   cleanupTests,
@@ -50,13 +49,16 @@ describe('Test a client controllers', function () {
 
   const playlistName = 'super playlist name'
   const playlistDescription = 'super playlist description'
 
   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/' ]
 
 
   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)
 
   before(async function () {
     this.timeout(120000)
 
@@ -79,7 +81,9 @@ describe('Test a client controllers', function () {
     const videos = resVideosRequest.body.data
     expect(videos.length).to.equal(1)
 
     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
 
 
     // Playlist
 
@@ -91,16 +95,14 @@ describe('Test a client controllers', function () {
     }
 
     const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
     }
 
     const 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,
 
     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
     })
 
     // Account
@@ -117,36 +119,43 @@ describe('Test a client controllers', function () {
 
     it('Should have valid oEmbed discovery tags for videos', async function () {
       for (const basePath of watchVideoBasePaths) {
 
     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) {
       }
     })
 
     it('Should have valid oEmbed discovery tags for a playlist', async function () {
       for (const basePath of watchPlaylistBasePaths) {
-        const res = await request(servers[0].url)
-          .get(basePath + playlistUUID)
-          .set('Accept', 'text/html')
-          .expect(HttpStatusCode.OK_200)
+        for (const id of playlistIds) {
+          const res = await makeGetRequest({
+            url: servers[0].url,
+            path: basePath + id,
+            accept: 'text/html',
+            statusCodeExpected: HttpStatusCode.OK_200
+          })
 
 
-        const port = servers[0].port
+          const port = servers[0].port
 
 
-        const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
-          `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlistUUID}" ` +
-          `title="${playlistName}" />`
+          const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
+            `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlist.uuid}" ` +
+            `title="${playlistName}" />`
 
 
-        expect(res.text).to.contain(expectedLink)
+          expect(res.text).to.contain(expectedLink)
+        }
       }
     })
   })
       }
     })
   })
@@ -190,7 +199,7 @@ describe('Test a client controllers', function () {
       expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
       expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
       expect(text).to.contain('<meta property="og:type" content="video" />')
       expect(text).to.contain(`<meta property="og: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 account page', async function () {
@@ -206,15 +215,19 @@ describe('Test a client controllers', function () {
     })
 
     it('Should have valid Open Graph tags on the watch page', async function () {
     })
 
     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 () {
     })
 
     it('Should have valid Open Graph tags on the watch playlist page', async function () {
-      await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
-      await watchPlaylistPageTest('/w/p/' + playlistUUID)
+      for (const path of watchPlaylistBasePaths) {
+        for (const id of playlistIds) {
+          await watchPlaylistPageTest(path + id)
+        }
+      }
     })
   })
 
     })
   })
 
@@ -263,15 +276,19 @@ describe('Test a client controllers', function () {
       }
 
       it('Should have valid twitter card on the watch video page', async function () {
       }
 
       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 () {
       })
 
       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 account page', async function () {
@@ -333,15 +350,19 @@ describe('Test a client controllers', function () {
       }
 
       it('Should have valid twitter card on the watch video page', async function () {
       }
 
       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 () {
       })
 
       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 account page', async function () {
@@ -399,8 +420,10 @@ describe('Test a client controllers', function () {
 
     it('Should use the original video URL for the canonical tag', async function () {
       for (const basePath of watchVideoBasePaths) {
 
     it('Should use the original video URL for the canonical tag', async function () {
       for (const basePath of watchVideoBasePaths) {
-        const res = await makeHTMLRequest(servers[1].url, basePath + servers[0].video.uuid)
-        expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
+        for (const id of videoIds) {
+          const res = await makeHTMLRequest(servers[1].url, basePath + id)
+          expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
+        }
       }
     })
 
       }
     })
 
@@ -426,8 +449,10 @@ describe('Test a client controllers', function () {
 
     it('Should use the original playlist URL for the canonical tag', async function () {
       for (const basePath of watchPlaylistBasePaths) {
 
     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}" />`)
+        }
       }
     })
   })
       }
     })
   })
index 63f7667a16632c8c4df6d82a71c98056633d2963..eb0a776b87b32ff8a107cc44abf23a79c0057dea 100644 (file)
@@ -4,7 +4,6 @@ registerTSPaths()
 import * as repl from 'repl'
 import * as path from 'path'
 import * as _ from 'lodash'
 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'
 import * as Sequelize from 'sequelize'
 import * as YoutubeDL from 'youtube-dl'
 import { initDatabaseModels, sequelizeTypescript } from '../initializers/database'
@@ -31,10 +30,6 @@ const start = async () => {
         env: process.env,
         lodash: _,
         path,
         env: process.env,
         lodash: _,
         path,
-        uuidv1,
-        uuidv3,
-        uuidv4,
-        uuidv5,
         cli,
         logger,
         constants,
         cli,
         logger,
         constants,
index d04757470d15bf65d73cc130ed79e77e042d8ada..28e431e94efee2ba7c9e04f58c2bb6eab67523bf 100644 (file)
@@ -43,6 +43,7 @@ interface ServerInfo {
   video?: {
     id: number
     uuid: string
   video?: {
     id: number
     uuid: string
+    shortUUID: string
     name?: string
     url?: string
 
     name?: string
     url?: string
 
index a3a276188f89e7a6e8970cfa12800fe3190ec5f9..469ea4d638cf9f3014114ade4f0b545b69674565 100644 (file)
@@ -6,9 +6,9 @@ import got, { Response as GotResponse } from 'got/dist/source'
 import * as parseTorrent from 'parse-torrent'
 import { join } from 'path'
 import * as request from 'supertest'
 import * 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 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'
 import { HttpStatusCode } from '@shared/core-utils'
 import { VideosCommonQuery } from '@shared/models'
 import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants'
@@ -806,7 +806,7 @@ async function uploadVideoAndGetId (options: {
 
   const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
 
 
   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 getLocalIdByUUID (url: string, uuid: string) {
@@ -827,7 +827,7 @@ async function uploadRandomVideoOnServers (servers: ServerInfo[], serverNumber:
 
 async function uploadRandomVideo (server: ServerInfo, wait = true, additionalParams: any = {}) {
   const prefixName = additionalParams.prefixName || ''
 
 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)
 
   const data = Object.assign({ name }, additionalParams)
   const res = await uploadVideo(server.url, server.accessToken, data)
diff --git a/shared/models/common/index.ts b/shared/models/common/index.ts
new file mode 100644 (file)
index 0000000..4db85ef
--- /dev/null
@@ -0,0 +1 @@
+export * from './result-list.model'
index 4db1f234efa6cbb038de6ae2a2530d7a2f258379..5c2bc480ee3f4ab938f74b2c8ee6e1bec0a1b44a 100644 (file)
@@ -1,16 +1,16 @@
 export * from './activitypub'
 export * from './actors'
 export * from './activitypub'
 export * from './actors'
-export * from './moderation'
-export * from './custom-markup'
 export * from './bulk'
 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 './feeds'
 export * from './joinpeertube'
+export * from './moderation'
 export * from './overviews'
 export * from './plugins'
 export * from './overviews'
 export * from './plugins'
+export * from './redundancy'
 export * from './search'
 export * from './server'
 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'
index 0e7e9587f7fadeb3d5a9562c5ae21b0ba435454c..7d35555c317862ac0adeaba7c864564a97f4174e 100644 (file)
@@ -10,7 +10,7 @@ export interface AbuseCreate {
   }
 
   video?: {
   }
 
   video?: {
-    id: number
+    id: number | string
     startAt?: number
     endAt?: number
   }
     startAt?: number
     endAt?: number
   }
diff --git a/shared/models/tokens/index.ts b/shared/models/tokens/index.ts
new file mode 100644 (file)
index 0000000..fe130f1
--- /dev/null
@@ -0,0 +1 @@
+export * from './oauth-client-local.model'
index 64f2c9df614ff1c78bd5cc50759be9f051ac97b8..faa9b98686818aeb64ab438067ddce17a8df6b1b 100644 (file)
@@ -35,3 +35,4 @@ export * from './video-transcoding-fps.model'
 
 export * from './video-update.model'
 export * from './video.model'
 
 export * from './video-update.model'
 export * from './video.model'
+export * from './video-create-result.model'
index 99f7e9bab4ec9d26d6573f516953b5ae9329f2e7..f11a4bd28ba66124f6a7285f28845388d223d567 100644 (file)
@@ -1,4 +1,5 @@
 export * from './video-exist-in-playlist.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'
 export * from './video-playlist-create.model'
 export * from './video-playlist-element-create.model'
 export * from './video-playlist-element-update.model'
diff --git a/shared/models/videos/playlist/video-playlist-create-result.model.ts b/shared/models/videos/playlist/video-playlist-create-result.model.ts
new file mode 100644 (file)
index 0000000..cd9b170
--- /dev/null
@@ -0,0 +1,5 @@
+export interface VideoPlaylistCreateResult {
+  id: number
+  uuid: string
+  shortUUID: string
+}
index ab4171ad126ed4ff406e63b627da680bbb33eb7d..b8a9955d9be9294d24257079b20063a917d55caf 100644 (file)
@@ -6,6 +6,8 @@ import { VideoPlaylistType } from './video-playlist-type.model'
 export interface VideoPlaylist {
   id: number
   uuid: string
 export interface VideoPlaylist {
   id: number
   uuid: string
+  shortUUID: string
+
   isLocal: boolean
 
   url: string
   isLocal: boolean
 
   url: string
diff --git a/shared/models/videos/video-create-result.model.ts b/shared/models/videos/video-create-result.model.ts
new file mode 100644 (file)
index 0000000..a9f8e25
--- /dev/null
@@ -0,0 +1,5 @@
+export interface VideoCreateResult {
+  id: number
+  uuid: string
+  shortUUID: string
+}
index caefeff82774980d6d1f4ea4fd44fde5a17de812..0e3e89f43b1777ce254d683138d45d1562de5055 100644 (file)
@@ -10,6 +10,8 @@ import { VideoStreamingPlaylist } from './video-streaming-playlist.model'
 export interface Video {
   id: number
   uuid: string
 export interface Video {
   id: number
   uuid: string
+  shortUUID: string
+
   createdAt: Date | string
   updatedAt: Date | string
   publishedAt: Date | string
   createdAt: Date | string
   updatedAt: Date | string
   publishedAt: Date | string
index 919905788f8eafbb46aa7ecef6c9caed839e8bde..1f9f3d5c476cc4a561110bf64a94918bc9eb8f5c 100644 (file)
@@ -3003,6 +3003,8 @@ paths:
                         $ref: '#/components/schemas/VideoPlaylist/properties/id'
                       uuid:
                         $ref: '#/components/schemas/VideoPlaylist/properties/uuid'
                         $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:
       requestBody:
         content:
           multipart/form-data:
@@ -4543,11 +4545,12 @@ components:
       name: id
       in: path
       required: true
       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'
       schema:
         oneOf:
           - $ref: '#/components/schemas/id'
           - $ref: '#/components/schemas/UUIDv4'
+          - $ref: '#/components/schemas/shortUUID'
     playlistId:
       name: playlistId
       in: path
     playlistId:
       name: playlistId
       in: path
@@ -4812,6 +4815,10 @@ components:
       pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
       minLength: 36
       maxLength: 36
       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
     username:
       type: string
       description: immutable name of the user, used to find or mention its actor
@@ -5141,6 +5148,9 @@ components:
           description: universal identifier for the video, that can be used across instances
           allOf:
             - $ref: '#/components/schemas/UUIDv4'
           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:
         isLive:
           type: boolean
         createdAt:
@@ -5520,6 +5530,9 @@ components:
           $ref: '#/components/schemas/id'
         uuid:
           $ref: '#/components/schemas/UUIDv4'
           $ref: '#/components/schemas/id'
         uuid:
           $ref: '#/components/schemas/UUIDv4'
+        shortUUID:
+          allOf:
+            - $ref: '#/components/schemas/shortUUID'
         createdAt:
           type: string
           format: date-time
         createdAt:
           type: string
           format: date-time
@@ -6295,6 +6308,8 @@ components:
               $ref: '#/components/schemas/Video/properties/id'
             uuid:
               $ref: '#/components/schemas/Video/properties/uuid'
               $ref: '#/components/schemas/Video/properties/id'
             uuid:
               $ref: '#/components/schemas/Video/properties/uuid'
+            shortUUID:
+              $ref: '#/components/schemas/Video/properties/shortUUID'
     CommentThreadResponse:
       properties:
         total:
     CommentThreadResponse:
       properties:
         total:
index 05295ea42aaf258a8daa85c820cb71ed298599f5..f68741038697eb827f5e3c28ed589861dffa67ed 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -7260,6 +7260,14 @@ shebang-regex@^3.0.0:
   resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
   integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
 
   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"
 side-channel@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"