Use global uuid instead of remoteId for videos

This commit is contained in:
Chocobozzz 2017-07-11 16:01:56 +02:00
parent e6d4b0ff24
commit 0a6658fdcb
58 changed files with 450 additions and 176 deletions

View File

@ -22,7 +22,7 @@ export class VideoAbuseService {
return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse') return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse')
} }
reportVideo (id: string, reason: string) { reportVideo (id: number, reason: string) {
const body = { const body = {
reason reason
} }

View File

@ -14,7 +14,8 @@ export class Video implements VideoServerModel {
description: string description: string
duration: number duration: number
durationLabel: string durationLabel: string
id: string id: number
uuid: string
isLocal: boolean isLocal: boolean
magnetUri: string magnetUri: string
name: string name: string
@ -51,7 +52,8 @@ export class Video implements VideoServerModel {
language: number language: number
description: string, description: string,
duration: number duration: number
id: string, id: number,
uuid: string,
isLocal: boolean, isLocal: boolean,
magnetUri: string, magnetUri: string,
name: string, name: string,
@ -75,6 +77,7 @@ export class Video implements VideoServerModel {
this.duration = hash.duration this.duration = hash.duration
this.durationLabel = Video.createDurationString(hash.duration) this.durationLabel = Video.createDurationString(hash.duration)
this.id = hash.id this.id = hash.id
this.uuid = hash.uuid
this.isLocal = hash.isLocal this.isLocal = hash.isLocal
this.magnetUri = hash.magnetUri this.magnetUri = hash.magnetUri
this.name = hash.name this.name = hash.name

View File

@ -52,8 +52,8 @@ export class VideoService {
return this.loadVideoAttributeEnum('languages', this.videoLanguages) return this.loadVideoAttributeEnum('languages', this.videoLanguages)
} }
getVideo (id: string): Observable<Video> { getVideo (uuid: string): Observable<Video> {
return this.http.get(VideoService.BASE_VIDEO_URL + id) return this.http.get(VideoService.BASE_VIDEO_URL + uuid)
.map(this.restExtractor.extractDataGet) .map(this.restExtractor.extractDataGet)
.map(videoHash => new Video(videoHash)) .map(videoHash => new Video(videoHash))
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
@ -89,7 +89,7 @@ export class VideoService {
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
} }
removeVideo (id: string) { removeVideo (id: number) {
return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)
.map(this.restExtractor.extractDataBool) .map(this.restExtractor.extractDataBool)
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
@ -106,7 +106,7 @@ export class VideoService {
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
} }
reportVideo (id: string, reason: string) { reportVideo (id: number, reason: string) {
const url = VideoService.BASE_VIDEO_URL + id + '/abuse' const url = VideoService.BASE_VIDEO_URL + id + '/abuse'
const body: VideoAbuseCreate = { const body: VideoAbuseCreate = {
reason reason
@ -117,15 +117,15 @@ export class VideoService {
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
} }
setVideoLike (id: string) { setVideoLike (id: number) {
return this.setVideoRate(id, 'like') return this.setVideoRate(id, 'like')
} }
setVideoDislike (id: string) { setVideoDislike (id: number) {
return this.setVideoRate(id, 'dislike') return this.setVideoRate(id, 'dislike')
} }
getUserVideoRating (id: string): Observable<UserVideoRate> { getUserVideoRating (id: number): Observable<UserVideoRate> {
const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating' const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating'
return this.authHttp.get(url) return this.authHttp.get(url)
@ -133,13 +133,13 @@ export class VideoService {
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
} }
blacklistVideo (id: string) { blacklistVideo (id: number) {
return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {}) return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {})
.map(this.restExtractor.extractDataBool) .map(this.restExtractor.extractDataBool)
.catch((res) => this.restExtractor.handleError(res)) .catch((res) => this.restExtractor.handleError(res))
} }
private setVideoRate (id: string, rateType: VideoRateType) { private setVideoRate (id: number, rateType: VideoRateType) {
const url = VideoService.BASE_VIDEO_URL + id + '/rate' const url = VideoService.BASE_VIDEO_URL + id + '/rate'
const body: UserVideoRateUpdate = { const body: UserVideoRateUpdate = {
rating: rateType rating: rateType

View File

@ -85,8 +85,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
this.videoLicences = this.videoService.videoLicences this.videoLicences = this.videoService.videoLicences
this.videoLanguages = this.videoService.videoLanguages this.videoLanguages = this.videoService.videoLanguages
const id = this.route.snapshot.params['id'] const uuid: string = this.route.snapshot.params['uuid']
this.videoService.getVideo(id) this.videoService.getVideo(uuid)
.subscribe( .subscribe(
video => { video => {
this.video = video this.video = video
@ -118,7 +118,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
.subscribe( .subscribe(
() => { () => {
this.notificationsService.success('Success', 'Video updated.') this.notificationsService.success('Success', 'Video updated.')
this.router.navigate([ '/videos/watch', this.video.id ]) this.router.navigate([ '/videos/watch', this.video.uuid ])
}, },
err => { err => {

View File

@ -1,6 +1,6 @@
<div class="video-miniature"> <div class="video-miniature">
<a <a
[routerLink]="['/videos/watch', video.id]" [attr.title]="video.description" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.description"
class="video-miniature-thumbnail" class="video-miniature-thumbnail"
> >
<img *ngIf="isVideoNSFWForThisUser() === false" [attr.src]="video.thumbnailUrl" alt="video thumbnail" /> <img *ngIf="isVideoNSFWForThisUser() === false" [attr.src]="video.thumbnailUrl" alt="video thumbnail" />
@ -16,7 +16,7 @@
<div class="video-miniature-informations"> <div class="video-miniature-informations">
<span class="video-miniature-name"> <span class="video-miniature-name">
<a [routerLink]="['/videos/watch', video.id]" [attr.title]="getVideoName()" class="video-miniature-name">{{ getVideoName() }}</a> <a [routerLink]="['/videos/watch', video.uuid]" [attr.title]="getVideoName()" class="video-miniature-name">{{ getVideoName() }}</a>
</span> </span>
<div class="video-miniature-tags"> <div class="video-miniature-tags">

View File

@ -27,7 +27,7 @@ export class VideoShareComponent {
getVideoIframeCode () { getVideoIframeCode () {
return '<iframe width="560" height="315" ' + return '<iframe width="560" height="315" ' +
'src="' + window.location.origin + '/videos/embed/' + this.video.id + '" ' + 'src="' + window.location.origin + '/videos/embed/' + this.video.uuid + '" ' +
'frameborder="0" allowfullscreen>' + 'frameborder="0" allowfullscreen>' +
'</iframe>' '</iframe>'
} }

View File

@ -65,7 +65,7 @@
<ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button"> <ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button">
<li *ngIf="canUserUpdateVideo()" role="menuitem"> <li *ngIf="canUserUpdateVideo()" role="menuitem">
<a class="dropdown-item" title="Update this video" href="#" [routerLink]="[ '/videos/edit', video.id ]"> <a class="dropdown-item" title="Update this video" href="#" [routerLink]="[ '/videos/edit', video.uuid ]">
<span class="glyphicon glyphicon-pencil"></span> Update <span class="glyphicon glyphicon-pencil"></span> Update
</a> </a>
</li> </li>

View File

@ -58,8 +58,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
ngOnInit () { ngOnInit () {
this.paramsSub = this.route.params.subscribe(routeParams => { this.paramsSub = this.route.params.subscribe(routeParams => {
let id = routeParams['id'] let uuid = routeParams['uuid']
this.videoService.getVideo(id).subscribe( this.videoService.getVideo(uuid).subscribe(
video => this.onVideoFetched(video), video => this.onVideoFetched(video),
error => { error => {

View File

@ -33,7 +33,7 @@ const videosRoutes: Routes = [
} }
}, },
{ {
path: 'edit/:id', path: 'edit/:uuid',
component: VideoUpdateComponent, component: VideoUpdateComponent,
data: { data: {
meta: { meta: {
@ -42,11 +42,11 @@ const videosRoutes: Routes = [
} }
}, },
{ {
path: ':id', path: ':uuid',
redirectTo: 'watch/:id' redirectTo: 'watch/:uuid'
}, },
{ {
path: 'watch/:id', path: 'watch/:uuid',
component: VideoWatchComponent component: VideoWatchComponent
} }
] ]

View File

@ -133,7 +133,7 @@ function processVideosEventsRetryWrapper (eventData: RemoteVideoEventData, fromP
function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) { function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) {
return db.sequelize.transaction(t => { return db.sequelize.transaction(t => {
return fetchOwnedVideo(eventData.remoteId) return fetchVideoByUUID(eventData.uuid)
.then(videoInstance => { .then(videoInstance => {
const options = { transaction: t } const options = { transaction: t }
@ -176,7 +176,7 @@ function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInsta
return quickAndDirtyUpdatesVideoToFriends(qadusParams, t) return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
}) })
}) })
.then(() => logger.info('Remote video event processed for video %s.', eventData.remoteId)) .then(() => logger.info('Remote video event processed for video %s.', eventData.uuid))
.catch(err => { .catch(err => {
logger.debug('Cannot process a video event.', err) logger.debug('Cannot process a video event.', err)
throw err throw err
@ -196,7 +196,7 @@ function quickAndDirtyUpdateVideo (videoData: RemoteQaduVideoData, fromPod: PodI
let videoName let videoName
return db.sequelize.transaction(t => { return db.sequelize.transaction(t => {
return fetchRemoteVideo(fromPod.host, videoData.remoteId) return fetchVideoByHostAndUUID(fromPod.host, videoData.uuid)
.then(videoInstance => { .then(videoInstance => {
const options = { transaction: t } const options = { transaction: t }
@ -232,12 +232,12 @@ function addRemoteVideoRetryWrapper (videoToCreateData: RemoteVideoCreateData, f
} }
function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) { function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
logger.debug('Adding remote video "%s".', videoToCreateData.remoteId) logger.debug('Adding remote video "%s".', videoToCreateData.uuid)
return db.sequelize.transaction(t => { return db.sequelize.transaction(t => {
return db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId) return db.Video.loadByUUID(videoToCreateData.uuid)
.then(video => { .then(video => {
if (video) throw new Error('RemoteId and host pair is not unique.') if (video) throw new Error('UUID already exists.')
return undefined return undefined
}) })
@ -257,7 +257,7 @@ function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodI
.then(({ author, tagInstances }) => { .then(({ author, tagInstances }) => {
const videoData = { const videoData = {
name: videoToCreateData.name, name: videoToCreateData.name,
remoteId: videoToCreateData.remoteId, uuid: videoToCreateData.uuid,
extname: videoToCreateData.extname, extname: videoToCreateData.extname,
infoHash: videoToCreateData.infoHash, infoHash: videoToCreateData.infoHash,
category: videoToCreateData.category, category: videoToCreateData.category,
@ -272,7 +272,8 @@ function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodI
updatedAt: videoToCreateData.updatedAt, updatedAt: videoToCreateData.updatedAt,
views: videoToCreateData.views, views: videoToCreateData.views,
likes: videoToCreateData.likes, likes: videoToCreateData.likes,
dislikes: videoToCreateData.dislikes dislikes: videoToCreateData.dislikes,
remote: true
} }
const video = db.Video.build(videoData) const video = db.Video.build(videoData)
@ -314,10 +315,10 @@ function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: RemoteVideoUpda
} }
function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) { function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
logger.debug('Updating remote video "%s".', videoAttributesToUpdate.remoteId) logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
return db.sequelize.transaction(t => { return db.sequelize.transaction(t => {
return fetchRemoteVideo(fromPod.host, videoAttributesToUpdate.remoteId) return fetchVideoByHostAndUUID(fromPod.host, videoAttributesToUpdate.uuid)
.then(videoInstance => { .then(videoInstance => {
const tags = videoAttributesToUpdate.tags const tags = videoAttributesToUpdate.tags
@ -359,18 +360,18 @@ function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, from
function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) { function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
// We need the instance because we have to remove some other stuffs (thumbnail etc) // We need the instance because we have to remove some other stuffs (thumbnail etc)
return fetchRemoteVideo(fromPod.host, videoToRemoveData.remoteId) return fetchVideoByHostAndUUID(fromPod.host, videoToRemoveData.uuid)
.then(video => { .then(video => {
logger.debug('Removing remote video %s.', video.remoteId) logger.debug('Removing remote video %s.', video.uuid)
return video.destroy() return video.destroy()
}) })
.catch(err => { .catch(err => {
logger.debug('Could not fetch remote video.', { host: fromPod.host, remoteId: videoToRemoveData.remoteId, error: err.stack }) logger.debug('Could not fetch remote video.', { host: fromPod.host, uuid: videoToRemoveData.uuid, error: err.stack })
}) })
} }
function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) { function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
return fetchOwnedVideo(reportData.videoRemoteId) return fetchVideoByUUID(reportData.videoUUID)
.then(video => { .then(video => {
logger.debug('Reporting remote abuse for video %s.', video.id) logger.debug('Reporting remote abuse for video %s.', video.id)
@ -386,8 +387,8 @@ function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod
.catch(err => logger.error('Cannot create remote abuse video.', err)) .catch(err => logger.error('Cannot create remote abuse video.', err))
} }
function fetchOwnedVideo (id: string) { function fetchVideoByUUID (id: string) {
return db.Video.load(id) return db.Video.loadByUUID(id)
.then(video => { .then(video => {
if (!video) throw new Error('Video not found') if (!video) throw new Error('Video not found')
@ -399,15 +400,15 @@ function fetchOwnedVideo (id: string) {
}) })
} }
function fetchRemoteVideo (podHost: string, remoteId: string) { function fetchVideoByHostAndUUID (podHost: string, uuid: string) {
return db.Video.loadByHostAndRemoteId(podHost, remoteId) return db.Video.loadByHostAndUUID(podHost, uuid)
.then(video => { .then(video => {
if (!video) throw new Error('Video not found') if (!video) throw new Error('Video not found')
return video return video
}) })
.catch(err => { .catch(err => {
logger.error('Cannot load video from host and remote id.', { error: err.stack, podHost, remoteId }) logger.error('Cannot load video from host and uuid.', { error: err.stack, podHost, uuid })
throw err throw err
}) })
} }

View File

@ -100,7 +100,7 @@ function getUserInformation (req: express.Request, res: express.Response, next:
} }
function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
const videoId = '' + req.params.videoId const videoId = +req.params.videoId
const userId = +res.locals.oauth.token.User.id const userId = +res.locals.oauth.token.User.id
db.UserVideoRate.load(userId, videoId, null) db.UserVideoRate.load(userId, videoId, null)

View File

@ -62,7 +62,7 @@ function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Respon
} }
function reportVideoAbuse (req: express.Request, res: express.Response) { function reportVideoAbuse (req: express.Request, res: express.Response) {
const videoInstance = res.locals.video const videoInstance = res.locals.video as VideoInstance
const reporterUsername = res.locals.oauth.token.User.username const reporterUsername = res.locals.oauth.token.User.username
const body: VideoAbuseCreate = req.body const body: VideoAbuseCreate = req.body
@ -81,7 +81,7 @@ function reportVideoAbuse (req: express.Request, res: express.Response) {
const reportData = { const reportData = {
reporterUsername, reporterUsername,
reportReason: abuse.reason, reportReason: abuse.reason,
videoRemoteId: videoInstance.remoteId videoUUID: videoInstance.uuid
} }
return friends.reportAbuseVideoToFriend(reportData, videoInstance, t).then(() => videoInstance) return friends.reportAbuseVideoToFriend(reportData, videoInstance, t).then(() => videoInstance)

View File

@ -176,7 +176,7 @@ function addVideo (req: express.Request, res: express.Response, videoFile: Expre
.then(({ author, tagInstances }) => { .then(({ author, tagInstances }) => {
const videoData = { const videoData = {
name: videoInfos.name, name: videoInfos.name,
remoteId: null, remote: false,
extname: path.extname(videoFile.filename), extname: path.extname(videoFile.filename),
category: videoInfos.category, category: videoInfos.category,
licence: videoInfos.licence, licence: videoInfos.licence,

View File

@ -69,7 +69,7 @@ function rateVideo (req: express.Request, res: express.Response) {
// There was a previous rate, update it // There was a previous rate, update it
if (previousRate) { if (previousRate) {
// We will remove the previous rate, so we will need to remove it from the video attribute // We will remove the previous rate, so we will need to update the video count attribute
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement-- if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--

View File

@ -78,7 +78,7 @@ function addOpenGraphTags (htmlStringPage: string, video: VideoInstance) {
} }
let tagsString = '' let tagsString = ''
Object.keys(metaTags).forEach(function (tagName) { Object.keys(metaTags).forEach(tagName => {
const tagValue = metaTags[tagName] const tagValue = metaTags[tagName]
tagsString += '<meta property="' + tagName + '" content="' + tagValue + '" />' tagsString += '<meta property="' + tagName + '" content="' + tagValue + '" />'
@ -89,13 +89,20 @@ function addOpenGraphTags (htmlStringPage: string, video: VideoInstance) {
function generateWatchHtmlPage (req: express.Request, res: express.Response, next: express.NextFunction) { function generateWatchHtmlPage (req: express.Request, res: express.Response, next: express.NextFunction) {
const videoId = '' + req.params.id const videoId = '' + req.params.id
let videoPromise: Promise<VideoInstance>
// Let Angular application handle errors // Let Angular application handle errors
if (!validator.isUUID(videoId, 4)) return res.sendFile(indexPath) if (validator.isUUID(videoId, 4)) {
videoPromise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(videoId)
} else if (validator.isInt(videoId)) {
videoPromise = db.Video.loadAndPopulateAuthorAndPodAndTags(+videoId)
} else {
return res.sendFile(indexPath)
}
Promise.all([ Promise.all([
readFileBufferPromise(indexPath), readFileBufferPromise(indexPath),
db.Video.loadAndPopulateAuthorAndPodAndTags(videoId) videoPromise
]) ])
.then(([ file, video ]) => { .then(([ file, video ]) => {
file = file as Buffer file = file as Buffer

View File

@ -9,7 +9,7 @@ import { isArray } from '../misc'
import { import {
isVideoAuthorValid, isVideoAuthorValid,
isVideoThumbnailDataValid, isVideoThumbnailDataValid,
isVideoRemoteIdValid, isVideoUUIDValid,
isVideoAbuseReasonValid, isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid, isVideoAbuseReporterUsernameValid,
isVideoViewsValid, isVideoViewsValid,
@ -50,11 +50,11 @@ function isEachRemoteRequestVideosValid (requests: any[]) {
) || ) ||
( (
isRequestTypeRemoveValid(request.type) && isRequestTypeRemoveValid(request.type) &&
isVideoRemoteIdValid(video.remoteId) isVideoUUIDValid(video.uuid)
) || ) ||
( (
isRequestTypeReportAbuseValid(request.type) && isRequestTypeReportAbuseValid(request.type) &&
isVideoRemoteIdValid(request.data.videoRemoteId) && isVideoUUIDValid(request.data.videoUUID) &&
isVideoAbuseReasonValid(request.data.reportReason) && isVideoAbuseReasonValid(request.data.reportReason) &&
isVideoAbuseReporterUsernameValid(request.data.reporterUsername) isVideoAbuseReporterUsernameValid(request.data.reporterUsername)
) )
@ -69,7 +69,7 @@ function isEachRemoteRequestVideosQaduValid (requests: any[]) {
if (!video) return false if (!video) return false
return ( return (
isVideoRemoteIdValid(video.remoteId) && isVideoUUIDValid(video.uuid) &&
(has(video, 'views') === false || isVideoViewsValid(video.views)) && (has(video, 'views') === false || isVideoViewsValid(video.views)) &&
(has(video, 'likes') === false || isVideoLikesValid(video.likes)) && (has(video, 'likes') === false || isVideoLikesValid(video.likes)) &&
(has(video, 'dislikes') === false || isVideoDislikesValid(video.dislikes)) (has(video, 'dislikes') === false || isVideoDislikesValid(video.dislikes))
@ -85,7 +85,7 @@ function isEachRemoteRequestVideosEventsValid (requests: any[]) {
if (!eventData) return false if (!eventData) return false
return ( return (
isVideoRemoteIdValid(eventData.remoteId) && isVideoUUIDValid(eventData.uuid) &&
values(REQUEST_VIDEO_EVENT_TYPES).indexOf(eventData.eventType) !== -1 && values(REQUEST_VIDEO_EVENT_TYPES).indexOf(eventData.eventType) !== -1 &&
isVideoEventCountValid(eventData.count) isVideoEventCountValid(eventData.count)
) )
@ -124,7 +124,7 @@ function isCommonVideoAttributesValid (video: any) {
isVideoInfoHashValid(video.infoHash) && isVideoInfoHashValid(video.infoHash) &&
isVideoNameValid(video.name) && isVideoNameValid(video.name) &&
isVideoTagsValid(video.tags) && isVideoTagsValid(video.tags) &&
isVideoRemoteIdValid(video.remoteId) && isVideoUUIDValid(video.uuid) &&
isVideoExtnameValid(video.extname) && isVideoExtnameValid(video.extname) &&
isVideoViewsValid(video.views) && isVideoViewsValid(video.views) &&
isVideoLikesValid(video.likes) && isVideoLikesValid(video.likes) &&

View File

@ -17,6 +17,10 @@ const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
function isVideoIdOrUUIDValid (value: string) {
return validator.isInt(value) || isVideoUUIDValid(value)
}
function isVideoAuthorValid (value: string) { function isVideoAuthorValid (value: string) {
return isUserUsernameValid(value) return isUserUsernameValid(value)
} }
@ -77,8 +81,8 @@ function isVideoThumbnailDataValid (value: string) {
return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA) return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
} }
function isVideoRemoteIdValid (value: string) { function isVideoUUIDValid (value: string) {
return exists(value) && validator.isUUID(value, 4) return exists(value) && validator.isUUID('' + value, 4)
} }
function isVideoAbuseReasonValid (value: string) { function isVideoAbuseReasonValid (value: string) {
@ -127,6 +131,7 @@ function isVideoFile (value: string, files: { [ fieldname: string ]: Express.Mul
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
isVideoIdOrUUIDValid,
isVideoAuthorValid, isVideoAuthorValid,
isVideoDateValid, isVideoDateValid,
isVideoCategoryValid, isVideoCategoryValid,
@ -141,7 +146,7 @@ export {
isVideoThumbnailValid, isVideoThumbnailValid,
isVideoThumbnailDataValid, isVideoThumbnailDataValid,
isVideoExtnameValid, isVideoExtnameValid,
isVideoRemoteIdValid, isVideoUUIDValid,
isVideoAbuseReasonValid, isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid, isVideoAbuseReporterUsernameValid,
isVideoFile, isVideoFile,
@ -155,6 +160,7 @@ export {
declare global { declare global {
namespace ExpressValidator { namespace ExpressValidator {
export interface Validator { export interface Validator {
isVideoIdOrUUIDValid,
isVideoAuthorValid, isVideoAuthorValid,
isVideoDateValid, isVideoDateValid,
isVideoCategoryValid, isVideoCategoryValid,
@ -169,7 +175,7 @@ declare global {
isVideoThumbnailValid, isVideoThumbnailValid,
isVideoThumbnailDataValid, isVideoThumbnailDataValid,
isVideoExtnameValid, isVideoExtnameValid,
isVideoRemoteIdValid, isVideoUUIDValid,
isVideoAbuseReasonValid, isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid, isVideoAbuseReporterUsernameValid,
isVideoFile, isVideoFile,

View File

@ -15,7 +15,7 @@ import {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const LAST_MIGRATION_VERSION = 50 const LAST_MIGRATION_VERSION = 55
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -26,7 +26,7 @@ function up (utils: {
}) })
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -25,7 +25,7 @@ function up (utils: {
}) })
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -17,7 +17,7 @@ function up (utils: {
return q.addColumn('Videos', 'views', data) return q.addColumn('Videos', 'views', data)
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -17,7 +17,7 @@ function up (utils: {
return q.addColumn('Videos', 'likes', data) return q.addColumn('Videos', 'likes', data)
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -17,7 +17,7 @@ function up (utils: {
return q.addColumn('Videos', 'dislikes', data) return q.addColumn('Videos', 'dislikes', data)
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -22,7 +22,7 @@ function up (utils: {
}) })
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -21,7 +21,7 @@ function up (utils: {
}) })
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -22,7 +22,7 @@ function up (utils: {
}) })
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -17,7 +17,7 @@ function up (utils: {
return q.addColumn('Users', 'displayNSFW', data) return q.addColumn('Users', 'displayNSFW', data)
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -17,7 +17,7 @@ function up (utils: {
return q.addColumn('Videos', 'language', data) return q.addColumn('Videos', 'language', data)
} }
function down (options, callback) { function down (options) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }

View File

@ -0,0 +1,157 @@
import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird'
function up (utils: {
transaction: Sequelize.Transaction,
queryInterface: Sequelize.QueryInterface,
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
const dataUUID = {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: true
}
return q.addColumn('Videos', 'uuid', dataUUID)
.then(() => {
const query = 'UPDATE "Videos" SET "uuid" = "id" WHERE "remoteId" IS NULL'
return utils.sequelize.query(query)
})
.then(() => {
const query = 'UPDATE "Videos" SET "uuid" = "remoteId" WHERE "remoteId" IS NOT NULL'
return utils.sequelize.query(query)
})
.then(() => {
dataUUID.defaultValue = null
return q.changeColumn('Videos', 'uuid', dataUUID)
})
.then(() => {
return removeForeignKey(utils.sequelize, 'RequestVideoQadus')
})
.then(() => {
return removeForeignKey(utils.sequelize, 'RequestVideoEvents')
})
.then(() => {
return removeForeignKey(utils.sequelize, 'BlacklistedVideos')
})
.then(() => {
return removeForeignKey(utils.sequelize, 'UserVideoRates')
})
.then(() => {
return removeForeignKey(utils.sequelize, 'VideoAbuses')
})
.then(() => {
return removeForeignKey(utils.sequelize, 'VideoTags')
})
.then(() => {
const query = 'ALTER TABLE "Videos" DROP CONSTRAINT "Videos_pkey"'
return utils.sequelize.query(query)
})
.then(() => {
const query = 'ALTER TABLE "Videos" ADD COLUMN "id2" SERIAL PRIMARY KEY'
return utils.sequelize.query(query)
})
.then(() => {
return q.renameColumn('Videos', 'id', 'oldId')
})
.then(() => {
return q.renameColumn('Videos', 'id2', 'id')
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'RequestVideoQadus', false)
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'RequestVideoEvents', false)
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'BlacklistedVideos', false)
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'UserVideoRates', false)
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'VideoAbuses', false)
})
.then(() => {
return changeForeignKey(q, utils.sequelize, 'VideoTags', true)
})
.then(() => {
return q.removeColumn('Videos', 'oldId')
})
.then(() => {
const dataRemote = {
type: Sequelize.BOOLEAN,
defaultValue: false,
allowNull: false
}
return q.addColumn('Videos', 'remote', dataRemote)
})
.then(() => {
const query = 'UPDATE "Videos" SET "remote" = false WHERE "remoteId" IS NULL'
return utils.sequelize.query(query)
})
.then(() => {
const query = 'UPDATE "Videos" SET "remote" = true WHERE "remoteId" IS NOT NULL'
return utils.sequelize.query(query)
})
.then(() => {
return q.removeColumn('Videos', 'remoteId')
})
}
function down (options) {
throw new Error('Not implemented.')
}
function removeForeignKey (sequelize: Sequelize.Sequelize, tableName: string) {
const query = 'ALTER TABLE "' + tableName + '" DROP CONSTRAINT "' + tableName + '_videoId_fkey' + '"'
return sequelize.query(query)
}
function changeForeignKey (q: Sequelize.QueryInterface, sequelize: Sequelize.Sequelize, tableName: string, allowNull: boolean) {
const data = {
type: Sequelize.INTEGER,
allowNull: true
}
return q.addColumn(tableName, 'videoId2', data)
.then(() => {
const query = 'UPDATE "' + tableName + '" SET "videoId2" = ' +
'(SELECT "id" FROM "Videos" WHERE "' + tableName + '"."videoId" = "Videos"."oldId")'
return sequelize.query(query)
})
.then(() => {
if (allowNull === false) {
data.allowNull = false
return q.changeColumn(tableName, 'videoId2', data)
}
return Promise.resolve()
})
.then(() => {
return q.removeColumn(tableName, 'videoId')
})
.then(() => {
return q.renameColumn(tableName, 'videoId2', 'videoId')
})
.then(() => {
return q.addIndex(tableName, [ 'videoId' ])
})
.then(() => {
const constraintName = tableName + '_videoId_fkey'
const query = 'ALTER TABLE "' + tableName + '" ' +
' ADD CONSTRAINT "' + constraintName + '"' +
' FOREIGN KEY ("videoId") REFERENCES "Videos" ON DELETE CASCADE'
return sequelize.query(query)
})
}
export {
up,
down
}

View File

@ -96,10 +96,10 @@ function executeMigration (actualVersion: number, entity: { version: string, scr
sequelize: db.sequelize sequelize: db.sequelize
} }
migrationScript.up(options) return migrationScript.up(options)
.then(() => { .then(() => {
// Update the new migration version // Update the new migration version
db.Application.updateMigrationVersion(versionScript, t) return db.Application.updateMigrationVersion(versionScript, t)
}) })
}) })
} }

View File

@ -43,8 +43,8 @@ import {
Pod as FormatedPod Pod as FormatedPod
} from '../../shared' } from '../../shared'
type QaduParam = { videoId: string, type: RequestVideoQaduType } type QaduParam = { videoId: number, type: RequestVideoQaduType }
type EventParam = { videoId: string, type: RequestVideoEventType } type EventParam = { videoId: number, type: RequestVideoEventType }
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]

View File

@ -3,8 +3,8 @@ import { logger } from '../../../helpers'
import { addVideoToFriends } from '../../../lib' import { addVideoToFriends } from '../../../lib'
import { VideoInstance } from '../../../models' import { VideoInstance } from '../../../models'
function process (data: { id: string }) { function process (data: { videoUUID: string }) {
return db.Video.loadAndPopulateAuthorAndPodAndTags(data.id).then(video => { return db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(data.videoUUID).then(video => {
return video.transcodeVideofile().then(() => video) return video.transcodeVideofile().then(() => video)
}) })
} }

View File

@ -12,7 +12,7 @@ import { RequestVideoEventType, RemoteVideoEventRequest, RemoteVideoEventType }
export type RequestVideoEventSchedulerOptions = { export type RequestVideoEventSchedulerOptions = {
type: RequestVideoEventType type: RequestVideoEventType
videoId: string videoId: number
count?: number count?: number
transaction?: Sequelize.Transaction transaction?: Sequelize.Transaction
} }
@ -49,7 +49,7 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
*/ */
const eventsPerVideoPerPod: { const eventsPerVideoPerPod: {
[ podId: string ]: { [ podId: string ]: {
[ videoRemoteId: string ]: { [ videoUUID: string ]: {
views?: number views?: number
likes?: number likes?: number
dislikes?: number dislikes?: number
@ -74,10 +74,10 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
requestsToMakeGrouped[toPodId].ids.push(eventToProcess.id) requestsToMakeGrouped[toPodId].ids.push(eventToProcess.id)
const eventsPerVideo = eventsPerVideoPerPod[toPodId] const eventsPerVideo = eventsPerVideoPerPod[toPodId]
const remoteId = eventToProcess.video.remoteId const uuid = eventToProcess.video.uuid
if (!eventsPerVideo[remoteId]) eventsPerVideo[remoteId] = {} if (!eventsPerVideo[uuid]) eventsPerVideo[uuid] = {}
const events = eventsPerVideo[remoteId] const events = eventsPerVideo[uuid]
if (!events[eventToProcess.type]) events[eventToProcess.type] = 0 if (!events[eventToProcess.type]) events[eventToProcess.type] = 0
events[eventToProcess.type] += eventToProcess.count events[eventToProcess.type] += eventToProcess.count
@ -88,13 +88,13 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
Object.keys(eventsPerVideoPerPod).forEach(toPodId => { Object.keys(eventsPerVideoPerPod).forEach(toPodId => {
const eventsForPod = eventsPerVideoPerPod[toPodId] const eventsForPod = eventsPerVideoPerPod[toPodId]
Object.keys(eventsForPod).forEach(remoteId => { Object.keys(eventsForPod).forEach(uuid => {
const eventsForVideo = eventsForPod[remoteId] const eventsForVideo = eventsForPod[uuid]
Object.keys(eventsForVideo).forEach(eventType => { Object.keys(eventsForVideo).forEach(eventType => {
requestsToMakeGrouped[toPodId].datas.push({ requestsToMakeGrouped[toPodId].datas.push({
data: { data: {
remoteId, uuid,
eventType: eventType as RemoteVideoEventType, eventType: eventType as RemoteVideoEventType,
count: +eventsForVideo[eventType] count: +eventsForVideo[eventType]
} }

View File

@ -21,8 +21,8 @@ interface RequestsObjectsCustom<U> extends RequestsObjects<U> {
datas: U[] datas: U[]
videos: { videos: {
[ id: string ]: { [ uuid: string ]: {
remoteId: string uuid: string
likes?: number likes?: number
dislikes?: number dislikes?: number
views?: number views?: number
@ -33,7 +33,7 @@ interface RequestsObjectsCustom<U> extends RequestsObjects<U> {
export type RequestVideoQaduSchedulerOptions = { export type RequestVideoQaduSchedulerOptions = {
type: RequestVideoQaduType type: RequestVideoQaduType
videoId: string videoId: number
transaction?: Sequelize.Transaction transaction?: Sequelize.Transaction
} }
@ -78,7 +78,7 @@ class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQa
// Maybe another attribute was filled for this video // Maybe another attribute was filled for this video
let videoData = requestsToMakeGrouped[hashKey].videos[video.id] let videoData = requestsToMakeGrouped[hashKey].videos[video.id]
if (!videoData) videoData = { remoteId: null } if (!videoData) videoData = { uuid: null }
switch (request.type) { switch (request.type) {
case REQUEST_VIDEO_QADU_TYPES.LIKES: case REQUEST_VIDEO_QADU_TYPES.LIKES:
@ -98,8 +98,8 @@ class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQa
return return
} }
// Do not forget the remoteId so the remote pod can identify the video // Do not forget the uuid so the remote pod can identify the video
videoData.remoteId = video.id videoData.uuid = video.uuid
requestsToMakeGrouped[hashKey].ids.push(request.id) requestsToMakeGrouped[hashKey].ids.push(request.id)
// Maybe there are multiple quick and dirty update for the same video // Maybe there are multiple quick and dirty update for the same video
@ -110,8 +110,8 @@ class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQa
// Now we deduped similar quick and dirty updates, we can build our requests datas // Now we deduped similar quick and dirty updates, we can build our requests datas
Object.keys(requestsToMakeGrouped).forEach(hashKey => { Object.keys(requestsToMakeGrouped).forEach(hashKey => {
Object.keys(requestsToMakeGrouped[hashKey].videos).forEach(videoId => { Object.keys(requestsToMakeGrouped[hashKey].videos).forEach(videoUUID => {
const videoData = requestsToMakeGrouped[hashKey].videos[videoId] const videoData = requestsToMakeGrouped[hashKey].videos[videoUUID]
requestsToMakeGrouped[hashKey].datas.push({ requestsToMakeGrouped[hashKey].datas.push({
data: videoData data: videoData

View File

@ -1,9 +1,12 @@
import 'express-validator' import 'express-validator'
import * as express from 'express' import * as express from 'express'
import * as Promise from 'bluebird'
import * as validator from 'validator'
import { database as db } from '../../initializers/database' import { database as db } from '../../initializers/database'
import { checkErrors } from './utils' import { checkErrors } from './utils'
import { logger } from '../../helpers' import { logger } from '../../helpers'
import { VideoInstance } from '../../models'
function usersAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function usersAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkBody('username', 'Should have a valid username').isUserUsernameValid() req.checkBody('username', 'Should have a valid username').isUserUsernameValid()
@ -59,12 +62,20 @@ function usersUpdateValidator (req: express.Request, res: express.Response, next
} }
function usersVideoRatingValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function usersVideoRatingValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('videoId', 'Should have a valid video id').notEmpty().isUUID(4) req.checkParams('videoId', 'Should have a valid video id').notEmpty().isVideoIdOrUUIDValid()
logger.debug('Checking usersVideoRating parameters', { parameters: req.params }) logger.debug('Checking usersVideoRating parameters', { parameters: req.params })
checkErrors(req, res, function () { checkErrors(req, res, function () {
db.Video.load(req.params.videoId) let videoPromise: Promise<VideoInstance>
if (validator.isUUID(req.params.videoId)) {
videoPromise = db.Video.loadByUUID(req.params.videoId)
} else {
videoPromise = db.Video.load(req.params.videoId)
}
videoPromise
.then(video => { .then(video => {
if (!video) return res.status(404).send('Video not found') if (!video) return res.status(404).send('Video not found')

View File

@ -1,10 +1,13 @@
import 'express-validator' import 'express-validator'
import * as express from 'express' import * as express from 'express'
import * as Promise from 'bluebird'
import * as validator from 'validator'
import { database as db } from '../../initializers/database' import { database as db } from '../../initializers/database'
import { checkErrors } from './utils' import { checkErrors } from './utils'
import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers'
import { logger, isVideoDurationValid } from '../../helpers' import { logger, isVideoDurationValid } from '../../helpers'
import { VideoInstance } from '../../models'
function videosAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videosAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
// FIXME: Don't write an error message, it seems there is a bug with express-validator // FIXME: Don't write an error message, it seems there is a bug with express-validator
@ -40,7 +43,7 @@ function videosAddValidator (req: express.Request, res: express.Response, next:
} }
function videosUpdateValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videosUpdateValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid() req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid()
req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid() req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid()
req.checkBody('licence', 'Should have a valid licence').optional().isVideoLicenceValid() req.checkBody('licence', 'Should have a valid licence').optional().isVideoLicenceValid()
@ -68,7 +71,7 @@ function videosUpdateValidator (req: express.Request, res: express.Response, nex
} }
function videosGetValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videosGetValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
logger.debug('Checking videosGet parameters', { parameters: req.params }) logger.debug('Checking videosGet parameters', { parameters: req.params })
@ -78,7 +81,7 @@ function videosGetValidator (req: express.Request, res: express.Response, next:
} }
function videosRemoveValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videosRemoveValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
logger.debug('Checking videosRemove parameters', { parameters: req.params }) logger.debug('Checking videosRemove parameters', { parameters: req.params })
@ -105,7 +108,7 @@ function videosSearchValidator (req: express.Request, res: express.Response, nex
} }
function videoAbuseReportValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videoAbuseReportValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid() req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid()
logger.debug('Checking videoAbuseReport parameters', { parameters: req.body }) logger.debug('Checking videoAbuseReport parameters', { parameters: req.body })
@ -116,7 +119,7 @@ function videoAbuseReportValidator (req: express.Request, res: express.Response,
} }
function videoRateValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videoRateValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
req.checkBody('rating', 'Should have a valid rate type').isVideoRatingTypeValid() req.checkBody('rating', 'Should have a valid rate type').isVideoRatingTypeValid()
logger.debug('Checking videoRate parameters', { parameters: req.body }) logger.debug('Checking videoRate parameters', { parameters: req.body })
@ -127,7 +130,7 @@ function videoRateValidator (req: express.Request, res: express.Response, next:
} }
function videosBlacklistValidator (req: express.Request, res: express.Response, next: express.NextFunction) { function videosBlacklistValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isVideoIdOrUUIDValid()
logger.debug('Checking videosBlacklist parameters', { parameters: req.params }) logger.debug('Checking videosBlacklist parameters', { parameters: req.params })
@ -157,7 +160,14 @@ export {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function checkVideoExists (id: string, res: express.Response, callback: () => void) { function checkVideoExists (id: string, res: express.Response, callback: () => void) {
db.Video.loadAndPopulateAuthorAndPodAndTags(id).then(video => { let promise: Promise<VideoInstance>
if (validator.isInt(id)) {
promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id)
} else { // UUID
promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id)
}
promise.then(video => {
if (!video) return res.status(404).send('Video not found') if (!video) return res.status(404).send('Video not found')
res.locals.video = video res.locals.video = video

View File

@ -4,7 +4,7 @@ import * as Promise from 'bluebird'
import { VideoRateType } from '../../../shared/models/videos/video-rate.type' import { VideoRateType } from '../../../shared/models/videos/video-rate.type'
export namespace UserVideoRateMethods { export namespace UserVideoRateMethods {
export type Load = (userId: number, videoId: string, transaction: Sequelize.Transaction) => Promise<UserVideoRateInstance> export type Load = (userId: number, videoId: number, transaction: Sequelize.Transaction) => Promise<UserVideoRateInstance>
} }
export interface UserVideoRateClass { export interface UserVideoRateClass {

View File

@ -65,7 +65,7 @@ function associate (models) {
}) })
} }
load = function (userId: number, videoId: string, transaction: Sequelize.Transaction) { load = function (userId: number, videoId: number, transaction: Sequelize.Transaction) {
const options: Sequelize.FindOptions = { const options: Sequelize.FindOptions = {
where: { where: {
userId, userId,

View File

@ -47,7 +47,7 @@ function associate (models) {
Tag.belongsToMany(models.Video, { Tag.belongsToMany(models.Video, {
foreignKey: 'tagId', foreignKey: 'tagId',
through: models.VideoTag, through: models.VideoTag,
onDelete: 'cascade' onDelete: 'CASCADE'
}) })
} }

View File

@ -20,7 +20,7 @@ export interface VideoAbuseClass {
export interface VideoAbuseAttributes { export interface VideoAbuseAttributes {
reporterUsername: string reporterUsername: string
reason: string reason: string
videoId: string videoId: number
} }
export interface VideoAbuseInstance extends VideoAbuseClass, VideoAbuseAttributes, Sequelize.Instance<VideoAbuseAttributes> { export interface VideoAbuseInstance extends VideoAbuseClass, VideoAbuseAttributes, Sequelize.Instance<VideoAbuseAttributes> {

View File

@ -96,7 +96,7 @@ function associate (models) {
name: 'reporterPodId', name: 'reporterPodId',
allowNull: true allowNull: true
}, },
onDelete: 'cascade' onDelete: 'CASCADE'
}) })
VideoAbuse.belongsTo(models.Video, { VideoAbuse.belongsTo(models.Video, {
@ -104,7 +104,7 @@ function associate (models) {
name: 'videoId', name: 'videoId',
allowNull: false allowNull: false
}, },
onDelete: 'cascade' onDelete: 'CASCADE'
}) })
} }

View File

@ -17,7 +17,7 @@ export namespace BlacklistedVideoMethods {
export type LoadById = (id: number) => Promise<BlacklistedVideoInstance> export type LoadById = (id: number) => Promise<BlacklistedVideoInstance>
export type LoadByVideoId = (id: string) => Promise<BlacklistedVideoInstance> export type LoadByVideoId = (id: number) => Promise<BlacklistedVideoInstance>
} }
export interface BlacklistedVideoClass { export interface BlacklistedVideoClass {
@ -30,7 +30,7 @@ export interface BlacklistedVideoClass {
} }
export interface BlacklistedVideoAttributes { export interface BlacklistedVideoAttributes {
videoId: string videoId: number
} }
export interface BlacklistedVideoInstance export interface BlacklistedVideoInstance

View File

@ -60,8 +60,11 @@ toFormatedJSON = function (this: BlacklistedVideoInstance) {
function associate (models) { function associate (models) {
BlacklistedVideo.belongsTo(models.Video, { BlacklistedVideo.belongsTo(models.Video, {
foreignKey: 'videoId', foreignKey: {
onDelete: 'cascade' name: 'videoId',
allowNull: false
},
onDelete: 'CASCADE'
}) })
} }
@ -92,7 +95,7 @@ loadById = function (id: number) {
return BlacklistedVideo.findById(id) return BlacklistedVideo.findById(id)
} }
loadByVideoId = function (id: string) { loadByVideoId = function (id: number) {
const query = { const query = {
where: { where: {
videoId: id videoId: id

View File

@ -9,6 +9,7 @@ import { Video as FormatedVideo } from '../../../shared/models/videos/video.mode
import { ResultList } from '../../../shared/models/result-list.model' import { ResultList } from '../../../shared/models/result-list.model'
export type FormatedAddRemoteVideo = { export type FormatedAddRemoteVideo = {
uuid: string
name: string name: string
category: number category: number
licence: number licence: number
@ -16,7 +17,6 @@ export type FormatedAddRemoteVideo = {
nsfw: boolean nsfw: boolean
description: string description: string
infoHash: string infoHash: string
remoteId: string
author: string author: string
duration: number duration: number
thumbnailData: string thumbnailData: string
@ -30,6 +30,7 @@ export type FormatedAddRemoteVideo = {
} }
export type FormatedUpdateRemoteVideo = { export type FormatedUpdateRemoteVideo = {
uuid: string
name: string name: string
category: number category: number
licence: number licence: number
@ -37,7 +38,6 @@ export type FormatedUpdateRemoteVideo = {
nsfw: boolean nsfw: boolean
description: string description: string
infoHash: string infoHash: string
remoteId: string
author: string author: string
duration: number duration: number
tags: string[] tags: string[]
@ -80,10 +80,12 @@ export namespace VideoMethods {
sort: string sort: string
) => Promise< ResultList<VideoInstance> > ) => Promise< ResultList<VideoInstance> >
export type Load = (id: string) => Promise<VideoInstance> export type Load = (id: number) => Promise<VideoInstance>
export type LoadByHostAndRemoteId = (fromHost: string, remoteId: string) => Promise<VideoInstance> export type LoadByUUID = (uuid: string) => Promise<VideoInstance>
export type LoadAndPopulateAuthor = (id: string) => Promise<VideoInstance> export type LoadByHostAndUUID = (fromHost: string, uuid: string) => Promise<VideoInstance>
export type LoadAndPopulateAuthorAndPodAndTags = (id: string) => Promise<VideoInstance> export type LoadAndPopulateAuthor = (id: number) => Promise<VideoInstance>
export type LoadAndPopulateAuthorAndPodAndTags = (id: number) => Promise<VideoInstance>
export type LoadByUUIDAndPopulateAuthorAndPodAndTags = (uuid: string) => Promise<VideoInstance>
} }
export interface VideoClass { export interface VideoClass {
@ -102,19 +104,21 @@ export interface VideoClass {
getDurationFromFile: VideoMethods.GetDurationFromFile getDurationFromFile: VideoMethods.GetDurationFromFile
list: VideoMethods.List list: VideoMethods.List
listForApi: VideoMethods.ListForApi listForApi: VideoMethods.ListForApi
loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId loadByHostAndUUID: VideoMethods.LoadByHostAndUUID
listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
listOwnedByAuthor: VideoMethods.ListOwnedByAuthor listOwnedByAuthor: VideoMethods.ListOwnedByAuthor
load: VideoMethods.Load load: VideoMethods.Load
loadByUUID: VideoMethods.LoadByUUID
loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor
loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags
loadByUUIDAndPopulateAuthorAndPodAndTags: VideoMethods.LoadByUUIDAndPopulateAuthorAndPodAndTags
searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags
} }
export interface VideoAttributes { export interface VideoAttributes {
uuid?: string
name: string name: string
extname: string extname: string
remoteId: string
category: number category: number
licence: number licence: number
language: number language: number
@ -125,13 +129,14 @@ export interface VideoAttributes {
views?: number views?: number
likes?: number likes?: number
dislikes?: number dislikes?: number
remote: boolean
Author?: AuthorInstance Author?: AuthorInstance
Tags?: TagInstance[] Tags?: TagInstance[]
} }
export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> { export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> {
id: string id: number
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date

View File

@ -62,21 +62,23 @@ let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
let getDurationFromFile: VideoMethods.GetDurationFromFile let getDurationFromFile: VideoMethods.GetDurationFromFile
let list: VideoMethods.List let list: VideoMethods.List
let listForApi: VideoMethods.ListForApi let listForApi: VideoMethods.ListForApi
let loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID
let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor
let load: VideoMethods.Load let load: VideoMethods.Load
let loadByUUID: VideoMethods.LoadByUUID
let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor
let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags
let loadByUUIDAndPopulateAuthorAndPodAndTags: VideoMethods.LoadByUUIDAndPopulateAuthorAndPodAndTags
let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
Video = sequelize.define<VideoInstance, VideoAttributes>('Video', Video = sequelize.define<VideoInstance, VideoAttributes>('Video',
{ {
id: { uuid: {
type: DataTypes.UUID, type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4, defaultValue: DataTypes.UUIDV4,
primaryKey: true, allowNull: false,
validate: { validate: {
isUUID: 4 isUUID: 4
} }
@ -95,13 +97,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
type: DataTypes.ENUM(values(CONSTRAINTS_FIELDS.VIDEOS.EXTNAME)), type: DataTypes.ENUM(values(CONSTRAINTS_FIELDS.VIDEOS.EXTNAME)),
allowNull: false allowNull: false
}, },
remoteId: {
type: DataTypes.UUID,
allowNull: true,
validate: {
isUUID: 4
}
},
category: { category: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
@ -199,6 +194,11 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
min: 0, min: 0,
isInt: true isInt: true
} }
},
remote: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
} }
}, },
{ {
@ -206,9 +206,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
{ {
fields: [ 'authorId' ] fields: [ 'authorId' ]
}, },
{
fields: [ 'remoteId' ]
},
{ {
fields: [ 'name' ] fields: [ 'name' ]
}, },
@ -226,6 +223,9 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
}, },
{ {
fields: [ 'likes' ] fields: [ 'likes' ]
},
{
fields: [ 'uuid' ]
} }
], ],
hooks: { hooks: {
@ -246,9 +246,11 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
listOwnedAndPopulateAuthorAndTags, listOwnedAndPopulateAuthorAndTags,
listOwnedByAuthor, listOwnedByAuthor,
load, load,
loadByHostAndRemoteId, loadByUUID,
loadByHostAndUUID,
loadAndPopulateAuthor, loadAndPopulateAuthor,
loadAndPopulateAuthorAndPodAndTags, loadAndPopulateAuthorAndPodAndTags,
loadByUUIDAndPopulateAuthorAndPodAndTags,
searchAndPopulateAuthorAndPodAndTags, searchAndPopulateAuthorAndPodAndTags,
removeFromBlacklist removeFromBlacklist
] ]
@ -289,8 +291,9 @@ function beforeCreate (video: VideoInstance, options: { transaction: Sequelize.T
) )
if (CONFIG.TRANSCODING.ENABLED === true) { if (CONFIG.TRANSCODING.ENABLED === true) {
// Put uuid because we don't have id auto incremented for now
const dataInput = { const dataInput = {
id: video.id videoUUID: video.uuid
} }
tasks.push( tasks.push(
@ -313,7 +316,7 @@ function afterDestroy (video: VideoInstance) {
if (video.isOwned()) { if (video.isOwned()) {
const removeVideoToFriendsParams = { const removeVideoToFriendsParams = {
remoteId: video.id uuid: video.uuid
} }
tasks.push( tasks.push(
@ -381,34 +384,27 @@ generateMagnetUri = function (this: VideoInstance) {
} }
getVideoFilename = function (this: VideoInstance) { getVideoFilename = function (this: VideoInstance) {
if (this.isOwned()) return this.id + this.extname return this.uuid + this.extname
return this.remoteId + this.extname
} }
getThumbnailName = function (this: VideoInstance) { getThumbnailName = function (this: VideoInstance) {
// We always have a copy of the thumbnail // We always have a copy of the thumbnail
return this.id + '.jpg' const extension = '.jpg'
return this.uuid + extension
} }
getPreviewName = function (this: VideoInstance) { getPreviewName = function (this: VideoInstance) {
const extension = '.jpg' const extension = '.jpg'
return this.uuid + extension
if (this.isOwned()) return this.id + extension
return this.remoteId + extension
} }
getTorrentName = function (this: VideoInstance) { getTorrentName = function (this: VideoInstance) {
const extension = '.torrent' const extension = '.torrent'
return this.uuid + extension
if (this.isOwned()) return this.id + extension
return this.remoteId + extension
} }
isOwned = function (this: VideoInstance) { isOwned = function (this: VideoInstance) {
return this.remoteId === null return this.remote === false
} }
toFormatedJSON = function (this: VideoInstance) { toFormatedJSON = function (this: VideoInstance) {
@ -435,6 +431,7 @@ toFormatedJSON = function (this: VideoInstance) {
const json = { const json = {
id: this.id, id: this.id,
uuid: this.uuid,
name: this.name, name: this.name,
category: this.category, category: this.category,
categoryLabel, categoryLabel,
@ -467,6 +464,7 @@ toAddRemoteJSON = function (this: VideoInstance) {
return readFileBufferPromise(thumbnailPath).then(thumbnailData => { return readFileBufferPromise(thumbnailPath).then(thumbnailData => {
const remoteVideo = { const remoteVideo = {
uuid: this.uuid,
name: this.name, name: this.name,
category: this.category, category: this.category,
licence: this.licence, licence: this.licence,
@ -474,7 +472,6 @@ toAddRemoteJSON = function (this: VideoInstance) {
nsfw: this.nsfw, nsfw: this.nsfw,
description: this.description, description: this.description,
infoHash: this.infoHash, infoHash: this.infoHash,
remoteId: this.id,
author: this.Author.name, author: this.Author.name,
duration: this.duration, duration: this.duration,
thumbnailData: thumbnailData.toString('binary'), thumbnailData: thumbnailData.toString('binary'),
@ -493,6 +490,7 @@ toAddRemoteJSON = function (this: VideoInstance) {
toUpdateRemoteJSON = function (this: VideoInstance) { toUpdateRemoteJSON = function (this: VideoInstance) {
const json = { const json = {
uuid: this.uuid,
name: this.name, name: this.name,
category: this.category, category: this.category,
licence: this.licence, licence: this.licence,
@ -500,7 +498,6 @@ toUpdateRemoteJSON = function (this: VideoInstance) {
nsfw: this.nsfw, nsfw: this.nsfw,
description: this.description, description: this.description,
infoHash: this.infoHash, infoHash: this.infoHash,
remoteId: this.id,
author: this.Author.name, author: this.Author.name,
duration: this.duration, duration: this.duration,
tags: map<TagInstance, string>(this.Tags, 'name'), tags: map<TagInstance, string>(this.Tags, 'name'),
@ -615,10 +612,10 @@ listForApi = function (start: number, count: number, sort: string) {
}) })
} }
loadByHostAndRemoteId = function (fromHost: string, remoteId: string) { loadByHostAndUUID = function (fromHost: string, uuid: string) {
const query = { const query = {
where: { where: {
remoteId: remoteId uuid
}, },
include: [ include: [
{ {
@ -640,10 +637,9 @@ loadByHostAndRemoteId = function (fromHost: string, remoteId: string) {
} }
listOwnedAndPopulateAuthorAndTags = function () { listOwnedAndPopulateAuthorAndTags = function () {
// If remoteId is null this is *our* video
const query = { const query = {
where: { where: {
remoteId: null remote: false
}, },
include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ] include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ]
} }
@ -654,7 +650,7 @@ listOwnedAndPopulateAuthorAndTags = function () {
listOwnedByAuthor = function (author: string) { listOwnedByAuthor = function (author: string) {
const query = { const query = {
where: { where: {
remoteId: null remote: false
}, },
include: [ include: [
{ {
@ -669,11 +665,20 @@ listOwnedByAuthor = function (author: string) {
return Video.findAll(query) return Video.findAll(query)
} }
load = function (id: string) { load = function (id: number) {
return Video.findById(id) return Video.findById(id)
} }
loadAndPopulateAuthor = function (id: string) { loadByUUID = function (uuid: string) {
const query = {
where: {
uuid
}
}
return Video.findOne(query)
}
loadAndPopulateAuthor = function (id: number) {
const options = { const options = {
include: [ Video['sequelize'].models.Author ] include: [ Video['sequelize'].models.Author ]
} }
@ -681,7 +686,7 @@ loadAndPopulateAuthor = function (id: string) {
return Video.findById(id, options) return Video.findById(id, options)
} }
loadAndPopulateAuthorAndPodAndTags = function (id: string) { loadAndPopulateAuthorAndPodAndTags = function (id: number) {
const options = { const options = {
include: [ include: [
{ {
@ -695,6 +700,23 @@ loadAndPopulateAuthorAndPodAndTags = function (id: string) {
return Video.findById(id, options) return Video.findById(id, options)
} }
loadByUUIDAndPopulateAuthorAndPodAndTags = function (uuid: string) {
const options = {
where: {
uuid
},
include: [
{
model: Video['sequelize'].models.Author,
include: [ { model: Video['sequelize'].models.Pod, required: false } ]
},
Video['sequelize'].models.Tag
]
}
return Video.findOne(options)
}
searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, start: number, count: number, sort: string) { searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, start: number, count: number, sort: string) {
const podInclude: Sequelize.IncludeOptions = { const podInclude: Sequelize.IncludeOptions = {
model: Video['sequelize'].models.Pod, model: Video['sequelize'].models.Pod,

View File

@ -44,7 +44,7 @@ describe('Test remote videos API validators', function () {
describe('When adding a video', function () { describe('When adding a video', function () {
it('Should check when adding a video') it('Should check when adding a video')
it('Should not add an existing remoteId and host pair') it('Should not add an existing uuid')
}) })
describe('When removing a video', function () { describe('When removing a video', function () {

View File

@ -20,6 +20,7 @@ const videosUtils = require('../utils/videos')
describe('Test multiple pods', function () { describe('Test multiple pods', function () {
let servers = [] let servers = []
const toRemove = [] const toRemove = []
let videoUUID = ''
before(function (done) { before(function (done) {
this.timeout(120000) this.timeout(120000)
@ -746,6 +747,36 @@ describe('Test multiple pods', function () {
expect(videos[0].name).not.to.equal(toRemove[1].name) expect(videos[0].name).not.to.equal(toRemove[1].name)
expect(videos[1].name).not.to.equal(toRemove[1].name) expect(videos[1].name).not.to.equal(toRemove[1].name)
videoUUID = videos[0].uuid
callback()
})
}, done)
})
it('Should get the same video by UUID on each pod', function (done) {
let baseVideo = null
each(servers, function (server, callback) {
videosUtils.getVideo(server.url, videoUUID, function (err, res) {
if (err) throw err
const video = res.body
if (baseVideo === null) {
baseVideo = video
return callback()
}
expect(baseVideo.name).to.equal(video.name)
expect(baseVideo.uuid).to.equal(video.uuid)
expect(baseVideo.category).to.equal(video.category)
expect(baseVideo.language).to.equal(video.language)
expect(baseVideo.licence).to.equal(video.licence)
expect(baseVideo.category).to.equal(video.category)
expect(baseVideo.nsfw).to.equal(video.nsfw)
expect(baseVideo.author).to.equal(video.author)
expect(baseVideo.tags).to.deep.equal(video.tags)
callback() callback()
}) })
}, done) }, done)

View File

@ -19,6 +19,7 @@ const videosUtils = require('../utils/videos')
describe('Test a single pod', function () { describe('Test a single pod', function () {
let server = null let server = null
let videoId = -1 let videoId = -1
let videoUUID = ''
let videosListBase = null let videosListBase = null
before(function (done) { before(function (done) {
@ -140,6 +141,7 @@ describe('Test a single pod', function () {
expect(test).to.equal(true) expect(test).to.equal(true)
videoId = video.id videoId = video.id
videoUUID = video.uuid
webtorrent.add(video.magnetUri, function (torrent) { webtorrent.add(video.magnetUri, function (torrent) {
expect(torrent.files).to.exist expect(torrent.files).to.exist
@ -187,12 +189,27 @@ describe('Test a single pod', function () {
}) })
}) })
it('Should get the video by UUID', function (done) {
// Yes, this could be long
this.timeout(60000)
videosUtils.getVideo(server.url, videoUUID, function (err, res) {
if (err) throw err
const video = res.body
expect(video.name).to.equal('my super name')
// Wait the async views increment
setTimeout(done, 500)
})
})
it('Should have the views updated', function (done) { it('Should have the views updated', function (done) {
videosUtils.getVideo(server.url, videoId, function (err, res) { videosUtils.getVideo(server.url, videoId, function (err, res) {
if (err) throw err if (err) throw err
const video = res.body const video = res.body
expect(video.views).to.equal(1) expect(video.views).to.equal(2)
done() done()
}) })

View File

@ -1,5 +1,5 @@
export interface RemoteQaduVideoData { export interface RemoteQaduVideoData {
remoteId: string uuid: string
views?: number views?: number
likes?: number likes?: number
dislikes?: number dislikes?: number

View File

@ -1,7 +1,7 @@
import { RemoteVideoRequest } from './remote-video-request.model' import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoCreateData { export interface RemoteVideoCreateData {
remoteId: string uuid: string
author: string author: string
tags: string[] tags: string[]
name: string name: string

View File

@ -1,7 +1,7 @@
export type RemoteVideoEventType = 'views' | 'likes' | 'dislikes' export type RemoteVideoEventType = 'views' | 'likes' | 'dislikes'
export interface RemoteVideoEventData { export interface RemoteVideoEventData {
remoteId: string uuid: string
eventType: RemoteVideoEventType eventType: RemoteVideoEventType
count: number count: number
} }

View File

@ -1,7 +1,7 @@
import { RemoteVideoRequest } from './remote-video-request.model' import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoRemoveData { export interface RemoteVideoRemoveData {
remoteId: string uuid: string
} }
export interface RemoteVideoRemoveRequest extends RemoteVideoRequest { export interface RemoteVideoRemoveRequest extends RemoteVideoRequest {

View File

@ -1,7 +1,7 @@
import { RemoteVideoRequest } from './remote-video-request.model' import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoReportAbuseData { export interface RemoteVideoReportAbuseData {
videoRemoteId: string videoUUID: string
reporterUsername: string reporterUsername: string
reportReason: string reportReason: string
} }

View File

@ -1,5 +1,5 @@
export interface RemoteVideoUpdateData { export interface RemoteVideoUpdateData {
remoteId: string uuid: string
tags: string[] tags: string[]
name: string name: string
extname: string extname: string

View File

@ -1,6 +1,6 @@
import { UserVideoRateType } from './user-video-rate.type' import { UserVideoRateType } from './user-video-rate.type'
export interface UserVideoRate { export interface UserVideoRate {
videoId: string videoId: number
rating: UserVideoRateType rating: UserVideoRateType
} }

View File

@ -3,6 +3,6 @@ export interface VideoAbuse {
reporterPodHost: string reporterPodHost: string
reason: string reason: string
reporterUsername: string reporterUsername: string
videoId: string videoId: number
createdAt: Date createdAt: Date
} }

View File

@ -1,5 +1,5 @@
export interface BlacklistedVideo { export interface BlacklistedVideo {
id: number id: number
videoId: string videoId: number
createdAt: Date createdAt: Date
} }

View File

@ -1,5 +1,6 @@
export interface Video { export interface Video {
id: string id: number
uuid: string
author: string author: string
createdAt: Date createdAt: Date
categoryLabel: string categoryLabel: string