]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Fix ownership change with a live video
authorChocobozzz <me@florianbigard.com>
Mon, 28 Jun 2021 09:54:40 +0000 (11:54 +0200)
committerChocobozzz <me@florianbigard.com>
Mon, 28 Jun 2021 09:54:40 +0000 (11:54 +0200)
server/middlewares/validators/videos/index.ts
server/middlewares/validators/videos/video-ownership-changes.ts [new file with mode: 0644]
server/middlewares/validators/videos/videos.ts
server/tests/api/videos/video-change-ownership.ts

index 1eabada0a2ce43fe7b0f25291dafbe67b2c7c669..369c2c9b63e1c15fc4c4f2caabc2110ba07bf221 100644 (file)
@@ -3,6 +3,8 @@ export * from './video-captions'
 export * from './video-channels'
 export * from './video-comments'
 export * from './video-imports'
+export * from './video-live'
+export * from './video-ownership-changes'
 export * from './video-watch'
 export * from './video-rates'
 export * from './video-shares'
diff --git a/server/middlewares/validators/videos/video-ownership-changes.ts b/server/middlewares/validators/videos/video-ownership-changes.ts
new file mode 100644 (file)
index 0000000..120b046
--- /dev/null
@@ -0,0 +1,119 @@
+import * as express from 'express'
+import { param } from 'express-validator'
+import { isIdOrUUIDValid } 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 { AccountModel } from '@server/models/account/account'
+import { MVideoWithAllFiles } from '@server/types/models'
+import { HttpStatusCode } from '@shared/core-utils'
+import { ServerErrorCode, UserRight, VideoChangeOwnershipAccept, VideoChangeOwnershipStatus, VideoState } from '@shared/models'
+import {
+  areValidationErrors,
+  checkUserCanManageVideo,
+  doesChangeVideoOwnershipExist,
+  doesVideoChannelOfAccountExist,
+  doesVideoExist
+} from '../shared'
+
+const videosChangeOwnershipValidator = [
+  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
+
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+    logger.debug('Checking changeOwnership parameters', { parameters: req.params })
+
+    if (areValidationErrors(req, res)) return
+    if (!await doesVideoExist(req.params.videoId, res)) return
+
+    // Check if the user who did the request is able to change the ownership of the video
+    if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return
+
+    const nextOwner = await AccountModel.loadLocalByName(req.body.username)
+    if (!nextOwner) {
+      res.fail({ message: 'Changing video ownership to a remote account is not supported yet' })
+      return
+    }
+
+    res.locals.nextOwner = nextOwner
+    return next()
+  }
+]
+
+const videosTerminateChangeOwnershipValidator = [
+  param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
+
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+    logger.debug('Checking changeOwnership parameters', { parameters: req.params })
+
+    if (areValidationErrors(req, res)) return
+    if (!await doesChangeVideoOwnershipExist(req.params.id, res)) return
+
+    // Check if the user who did the request is able to change the ownership of the video
+    if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
+
+    const videoChangeOwnership = res.locals.videoChangeOwnership
+
+    if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
+      res.fail({
+        status: HttpStatusCode.FORBIDDEN_403,
+        message: 'Ownership already accepted or refused'
+      })
+      return
+    }
+
+    return next()
+  }
+]
+
+const videosAcceptChangeOwnershipValidator = [
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+    const body = req.body as VideoChangeOwnershipAccept
+    if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return
+
+    const videoChangeOwnership = res.locals.videoChangeOwnership
+
+    const video = videoChangeOwnership.Video
+
+    if (!await checkCanAccept(video, res)) return
+
+    return next()
+  }
+]
+
+export {
+  videosChangeOwnershipValidator,
+  videosTerminateChangeOwnershipValidator,
+  videosAcceptChangeOwnershipValidator
+}
+
+// ---------------------------------------------------------------------------
+
+async function checkCanAccept (video: MVideoWithAllFiles, res: express.Response): Promise<boolean> {
+  if (video.isLive) {
+
+    if (video.state !== VideoState.WAITING_FOR_LIVE) {
+      res.fail({
+        status: HttpStatusCode.BAD_REQUEST_400,
+        message: 'You can accept an ownership change of a published live.'
+      })
+
+      return false
+    }
+
+    return true
+  }
+
+  const user = res.locals.oauth.token.User
+
+  if (!await isAbleToUploadVideo(user.id, video.getMaxQualityFile().size)) {
+    res.fail({
+      status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
+      message: 'The user video quota is exceeded with this video.',
+      type: ServerErrorCode.QUOTA_REACHED
+    })
+
+    return false
+  }
+
+  return true
+}
index 2bed5f18123b09ff9e5ce1a4538d1ab2b7902ee5..8201e80c304a395c22078bda05efde93f8a6f3aa 100644 (file)
@@ -5,9 +5,8 @@ import { isAbleToUploadVideo } from '@server/lib/user'
 import { getServerActor } from '@server/models/application/application'
 import { ExpressPromiseHandler } from '@server/types/express'
 import { MUserAccountId, MVideoFullLight } from '@server/types/models'
-import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared'
+import { ServerErrorCode, UserRight, VideoPrivacy } from '../../../../shared'
 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
-import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/change-ownership/video-change-ownership-accept.model'
 import {
   exists,
   isBooleanValid,
@@ -22,7 +21,6 @@ import {
   toValueOrNull
 } from '../../../helpers/custom-validators/misc'
 import { isBooleanBothQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search'
-import { checkUserCanTerminateOwnershipChange } from '../../../helpers/custom-validators/video-ownership'
 import {
   isScheduleVideoUpdatePrivacyValid,
   isVideoCategoryValid,
@@ -48,13 +46,11 @@ import { CONFIG } from '../../../initializers/config'
 import { CONSTRAINTS_FIELDS, OVERVIEWS } from '../../../initializers/constants'
 import { isLocalVideoAccepted } from '../../../lib/moderation'
 import { Hooks } from '../../../lib/plugins/hooks'
-import { AccountModel } from '../../../models/account/account'
 import { VideoModel } from '../../../models/video/video'
 import { authenticatePromiseIfNeeded } from '../../auth'
 import {
   areValidationErrors,
   checkUserCanManageVideo,
-  doesChangeVideoOwnershipExist,
   doesVideoChannelOfAccountExist,
   doesVideoExist,
   doesVideoFileOfVideoExist
@@ -342,76 +338,6 @@ const videosRemoveValidator = [
   }
 ]
 
-const videosChangeOwnershipValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
-
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking changeOwnership parameters', { parameters: req.params })
-
-    if (areValidationErrors(req, res)) return
-    if (!await doesVideoExist(req.params.videoId, res)) return
-
-    // Check if the user who did the request is able to change the ownership of the video
-    if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return
-
-    const nextOwner = await AccountModel.loadLocalByName(req.body.username)
-    if (!nextOwner) {
-      res.fail({ message: 'Changing video ownership to a remote account is not supported yet' })
-      return
-    }
-
-    res.locals.nextOwner = nextOwner
-    return next()
-  }
-]
-
-const videosTerminateChangeOwnershipValidator = [
-  param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
-
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking changeOwnership parameters', { parameters: req.params })
-
-    if (areValidationErrors(req, res)) return
-    if (!await doesChangeVideoOwnershipExist(req.params.id, res)) return
-
-    // Check if the user who did the request is able to change the ownership of the video
-    if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
-
-    const videoChangeOwnership = res.locals.videoChangeOwnership
-
-    if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
-      res.fail({
-        status: HttpStatusCode.FORBIDDEN_403,
-        message: 'Ownership already accepted or refused'
-      })
-      return
-    }
-
-    return next()
-  }
-]
-
-const videosAcceptChangeOwnershipValidator = [
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    const body = req.body as VideoChangeOwnershipAccept
-    if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return
-
-    const user = res.locals.oauth.token.User
-    const videoChangeOwnership = res.locals.videoChangeOwnership
-    const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size)
-    if (isAble === false) {
-      res.fail({
-        status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
-        message: 'The user video quota is exceeded with this video.',
-        type: ServerErrorCode.QUOTA_REACHED
-      })
-      return
-    }
-
-    return next()
-  }
-]
-
 const videosOverviewValidator = [
   query('page')
     .optional()
@@ -578,10 +504,6 @@ export {
   videosCustomGetValidator,
   videosRemoveValidator,
 
-  videosChangeOwnershipValidator,
-  videosTerminateChangeOwnershipValidator,
-  videosAcceptChangeOwnershipValidator,
-
   getCommonVideoEditAttributes,
 
   commonVideosFiltersValidator,
index fad4c8b1fb036c8934a8a32dc6cfebb29e0bd1b7..a3384851b72a2cf4c69448bcfd38de213cbc1f45 100644 (file)
@@ -1,11 +1,13 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
-import * as chai from 'chai'
 import 'mocha'
+import * as chai from 'chai'
+import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
 import {
   acceptChangeOwnership,
   changeVideoOwnership,
   cleanupTests,
+  createLive,
   createUser,
   doubleFollow,
   flushAndRunMultipleServers,
@@ -17,13 +19,14 @@ import {
   refuseChangeOwnership,
   ServerInfo,
   setAccessTokensToServers,
+  setDefaultVideoChannel,
+  updateCustomSubConfig,
   uploadVideo,
   userLogin
 } from '../../../../shared/extra-utils'
 import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { User } from '../../../../shared/models/users'
-import { VideoDetails } from '../../../../shared/models/videos'
-import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
+import { VideoDetails, VideoPrivacy } from '../../../../shared/models/videos'
 
 const expect = chai.expect
 
@@ -37,15 +40,32 @@ describe('Test video change ownership - nominal', function () {
     username: 'second',
     password: 'My other password'
   }
+
   let firstUserAccessToken = ''
+  let firstUserChannelId: number
+
   let secondUserAccessToken = ''
+  let secondUserChannelId: number
+
   let lastRequestChangeOwnershipId = ''
 
+  let liveId: number
+
   before(async function () {
     this.timeout(50000)
 
     servers = await flushAndRunMultipleServers(2)
     await setAccessTokensToServers(servers)
+    await setDefaultVideoChannel(servers)
+
+    await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
+      transcoding: {
+        enabled: false
+      },
+      live: {
+        enabled: true
+      }
+    })
 
     const videoQuota = 42000000
     await createUser({
@@ -66,22 +86,35 @@ describe('Test video change ownership - nominal', function () {
     firstUserAccessToken = await userLogin(servers[0], firstUser)
     secondUserAccessToken = await userLogin(servers[0], secondUser)
 
-    const videoAttributes = {
-      name: 'my super name',
-      description: 'my super description'
+    {
+      const res = await getMyUserInformation(servers[0].url, firstUserAccessToken)
+      const firstUserInformation: User = res.body
+      firstUserChannelId = firstUserInformation.videoChannels[0].id
     }
-    await uploadVideo(servers[0].url, firstUserAccessToken, videoAttributes)
 
-    await waitJobs(servers)
+    {
+      const res = await getMyUserInformation(servers[0].url, secondUserAccessToken)
+      const secondUserInformation: User = res.body
+      secondUserChannelId = secondUserInformation.videoChannels[0].id
+    }
 
-    const res = await getVideosList(servers[0].url)
-    const videos = res.body.data
+    {
+      const videoAttributes = {
+        name: 'my super name',
+        description: 'my super description'
+      }
+      const res = await uploadVideo(servers[0].url, firstUserAccessToken, videoAttributes)
 
-    expect(videos.length).to.equal(1)
+      const resVideo = await getVideo(servers[0].url, res.body.video.id)
+      servers[0].video = resVideo.body
+    }
 
-    const video = videos.find(video => video.name === 'my super name')
-    expect(video.channel.name).to.equal('first_channel')
-    servers[0].video = video
+    {
+      const attributes = { name: 'live', channelId: firstUserChannelId, privacy: VideoPrivacy.PUBLIC }
+      const res = await createLive(servers[0].url, firstUserAccessToken, attributes)
+
+      liveId = res.body.video.id
+    }
 
     await doubleFollow(servers[0], servers[1])
   })
@@ -175,19 +208,19 @@ describe('Test video change ownership - nominal', function () {
   it('Should not be possible to accept the change of ownership from first user', async function () {
     this.timeout(10000)
 
-    const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken)
-    const secondUserInformation: User = secondUserInformationResponse.body
-    const channelId = secondUserInformation.videoChannels[0].id
-    await acceptChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, HttpStatusCode.FORBIDDEN_403)
+    await acceptChangeOwnership(
+      servers[0].url,
+      firstUserAccessToken,
+      lastRequestChangeOwnershipId,
+      secondUserChannelId,
+      HttpStatusCode.FORBIDDEN_403
+    )
   })
 
   it('Should be possible to accept the change of ownership from second user', async function () {
     this.timeout(10000)
 
-    const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken)
-    const secondUserInformation: User = secondUserInformationResponse.body
-    const channelId = secondUserInformation.videoChannels[0].id
-    await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, channelId)
+    await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, secondUserChannelId)
 
     await waitJobs(servers)
   })
@@ -204,6 +237,37 @@ describe('Test video change ownership - nominal', function () {
     }
   })
 
+  it('Should send a request to change ownership of a live', async function () {
+    this.timeout(15000)
+
+    await changeVideoOwnership(servers[0].url, firstUserAccessToken, liveId, secondUser.username)
+
+    const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken)
+
+    expect(resSecondUser.body.total).to.equal(3)
+    expect(resSecondUser.body.data.length).to.equal(3)
+
+    lastRequestChangeOwnershipId = resSecondUser.body.data[0].id
+  })
+
+  it('Should accept a live ownership change', async function () {
+    this.timeout(20000)
+
+    await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, secondUserChannelId)
+
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getVideo(server.url, servers[0].video.uuid)
+
+      const video: VideoDetails = res.body
+
+      expect(video.name).to.equal('my super name')
+      expect(video.channel.displayName).to.equal('Main second channel')
+      expect(video.channel.name).to.equal('second_channel')
+    }
+  })
+
   after(async function () {
     await cleanupTests(servers)
   })