Add tests and fix bugs for video privacy
authorChocobozzz <florian.bigard@gmail.com>
Tue, 31 Oct 2017 14:20:35 +0000 (15:20 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Tue, 31 Oct 2017 14:32:10 +0000 (15:32 +0100)
server/controllers/api/users.ts
server/middlewares/validators/videos.ts
server/tests/api/check-params/videos.ts
server/tests/api/index.ts
server/tests/api/single-pod.ts
server/tests/api/users.ts
server/tests/api/video-privacy.ts [new file with mode: 0644]
server/tests/utils/videos.ts

index dcd407fdf49b298cd6134a9878a6518196079544..bacfc4552614ab12bea9d9f39f307774c6f13408 100644 (file)
@@ -171,7 +171,7 @@ async function getUserInformation (req: express.Request, res: express.Response,
 }
 
 function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
-  return res.json(res.locals.oauth.token.User.toFormattedJSON())
+  return res.json(res.locals.user.toFormattedJSON())
 }
 
 async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
index e197d46069c09bc3b8ef0465b972078dbfa350eb..15b4629c126d3f205892dad993e6d61df8b8982d 100644 (file)
@@ -24,6 +24,7 @@ import {
   isVideoPrivacyValid
 } from '../../helpers'
 import { UserRight, VideoPrivacy } from '../../../shared'
+import { authenticate } from '../oauth'
 
 const videosAddValidator = [
   body('videofile').custom((value, { req }) => isVideoFile(req.files)).withMessage(
@@ -112,7 +113,7 @@ const videosUpdateValidator = [
   body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
   body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'),
   body('nsfw').optional().custom(isVideoNSFWValid).withMessage('Should have a valid NSFW attribute'),
-  body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
+  body('privacy').optional().custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
   body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
   body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
 
@@ -155,7 +156,22 @@ const videosGetValidator = [
     logger.debug('Checking videosGet parameters', { parameters: req.params })
 
     checkErrors(req, res, () => {
-      checkVideoExists(req.params.id, res, next)
+      checkVideoExists(req.params.id, res, () => {
+        const video = res.locals.video
+
+        // Video is not private, anyone can access it
+        if (video.privacy !== VideoPrivacy.PRIVATE) return next()
+
+        authenticate(req, res, () => {
+          if (video.VideoChannel.Author.userId !== res.locals.oauth.token.User.id) {
+            return res.status(403)
+              .json({ error: 'Cannot get this private video of another user' })
+              .end()
+          }
+
+          next()
+        })
+      })
     })
   }
 ]
@@ -232,28 +248,23 @@ export {
 
 function checkUserCanDeleteVideo (userId: number, res: express.Response, callback: () => void) {
   // Retrieve the user who did the request
-  db.User.loadById(userId)
-    .then(user => {
-      if (res.locals.video.isOwned() === false) {
-        return res.status(403)
-                  .json({ error: 'Cannot remove video of another pod, blacklist it' })
-                  .end()
-      }
-
-      // Check if the user can delete the video
-      // The user can delete it if s/he is an admin
-      // Or if s/he is the video's author
-      if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && res.locals.video.Author.userId !== res.locals.oauth.token.User.id) {
-        return res.status(403)
-                  .json({ error: 'Cannot remove video of another user' })
-                  .end()
-      }
-
-      // If we reach this comment, we can delete the video
-      callback()
-    })
-    .catch(err => {
-      logger.error('Error in video request validator.', err)
-      return res.sendStatus(500)
-    })
+  if (res.locals.video.isOwned() === false) {
+    return res.status(403)
+              .json({ error: 'Cannot remove video of another pod, blacklist it' })
+              .end()
+  }
+
+  // Check if the user can delete the video
+  // The user can delete it if s/he is an admin
+  // Or if s/he is the video's author
+  const author = res.locals.video.VideoChannel.Author
+  const user = res.locals.oauth.token.User
+  if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && author.userId !== user.id) {
+    return res.status(403)
+              .json({ error: 'Cannot remove video of another user' })
+              .end()
+  }
+
+  // If we reach this comment, we can delete the video
+  callback()
 }
index c59f5da93d1b56085742aa61967908ec9ed932bd..5860e91951bd6d719308073fce768fbc475aa4ba 100644 (file)
@@ -19,12 +19,46 @@ import {
   createUser,
   getUserAccessToken
 } from '../../utils'
+import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
 
 describe('Test videos API validator', function () {
   const path = '/api/v1/videos/'
   let server: ServerInfo
   let channelId: number
 
+  function getCompleteVideoUploadAttributes () {
+    return {
+      name: 'my super name',
+      category: 5,
+      licence: 1,
+      language: 6,
+      nsfw: false,
+      description: 'my super description',
+      tags: [ 'tag1', 'tag2' ],
+      privacy: VideoPrivacy.PUBLIC,
+      channelId
+    }
+  }
+
+  function getCompleteVideoUpdateAttributes () {
+    return {
+      name: 'my super name',
+      category: 5,
+      licence: 2,
+      language: 6,
+      nsfw: false,
+      description: 'my super description',
+      privacy: VideoPrivacy.PUBLIC,
+      tags: [ 'tag1', 'tag2' ]
+    }
+  }
+
+  function getVideoUploadAttaches () {
+    return {
+      'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
+    }
+  }
+
   // ---------------------------------------------------------------
 
   before(async function () {
@@ -99,6 +133,37 @@ describe('Test videos API validator', function () {
     })
   })
 
+  describe('When listing my videos', function () {
+    const path = '/api/v1/users/me/videos'
+
+    it('Should fail with a bad start pagination', async function () {
+      await request(server.url)
+        .get(path)
+        .set('Authorization', 'Bearer ' + server.accessToken)
+        .query({ start: 'hello' })
+        .set('Accept', 'application/json')
+        .expect(400)
+    })
+
+    it('Should fail with a bad count pagination', async function () {
+      await request(server.url)
+        .get(path)
+        .set('Authorization', 'Bearer ' + server.accessToken)
+        .query({ count: 'hello' })
+        .set('Accept', 'application/json')
+        .expect(400)
+    })
+
+    it('Should fail with an incorrect sort', async function () {
+      await request(server.url)
+        .get(path)
+        .set('Authorization', 'Bearer ' + server.accessToken)
+        .query({ sort: 'hello' })
+        .set('Accept', 'application/json')
+        .expect(400)
+    })
+  })
+
   describe('When adding a video', function () {
     it('Should fail with nothing', async function () {
       const fields = {}
@@ -107,219 +172,108 @@ describe('Test videos API validator', function () {
     })
 
     it('Should fail without name', async function () {
-      const fields = {
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.name
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a long name', async function () {
-      const fields = {
-        name: 'My very very very very very very very very very very very very very very very very very  ' +
-              'very very very very very very very very very very very very very very very very long long' +
-              'very very very very very very very very very very very very very very very very long name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.name = 'My very very very very very very very very very very very very very very very very very  ' +
+                    'very very very very very very very very very very very very very very very very long long' +
+                    'very very very very very very very very very very very very very very very very long name'
+
+      const attaches = getVideoUploadAttaches
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without a category', async function () {
-      const fields = {
-        name: 'my super name',
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.category
+
+      const attaches = getVideoUploadAttaches
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a bad category', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 125,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.category = 125
+
+      const attaches = getVideoUploadAttaches
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without a licence', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.licence
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a bad licence', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 125,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.licence = 125
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a bad language', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 4,
-        language: 563,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.language = 563
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without nsfw attribute', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 4,
-        language: 6,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.nsfw
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a bad nsfw attribute', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 4,
-        language: 6,
-        nsfw: 2,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.nsfw = 2 as any
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without description', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.description
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a long description', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description which is very very very very very very very very very very very very very very long'.repeat(35),
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.description = 'my super description which is very very very very very very very very very very very very long'.repeat(35)
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without a channel', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      delete fields.channelId
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a bad channel', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId: 545454
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.channelId = 545454
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
@@ -332,101 +286,47 @@ describe('Test videos API validator', function () {
 
       const accessTokenUser = await getUserAccessToken(server, user)
       const res = await getMyUserInformation(server.url, accessTokenUser)
-      const channelId = res.body.videoChannels[0].id
+      const customChannelId = res.body.videoChannels[0].id
 
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.channelId = customChannelId
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with too many tags', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.tags = [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ]
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a tag length too low', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 't' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.tags = [ 'tag1', 't' ]
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail with a tag length too big', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'my_super_tag_too_long_long_long_long_long_long', 'tag1' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      fields.tags = [ 'my_super_tag_too_long_long_long_long_long_long', 'tag1' ]
+
+      const attaches = getVideoUploadAttaches()
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without an input file', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
+      const fields = getCompleteVideoUploadAttributes()
       const attaches = {}
       await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
     })
 
     it('Should fail without an incorrect input file', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
+      const fields = getCompleteVideoUploadAttributes()
       const attaches = {
         'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
       }
@@ -434,16 +334,7 @@ describe('Test videos API validator', function () {
     })
 
     it('Should fail with a too big duration', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
+      const fields = getCompleteVideoUploadAttributes()
       const attaches = {
         'videofile': join(__dirname, '..', 'fixtures', 'video_too_long.webm')
       }
@@ -453,19 +344,8 @@ describe('Test videos API validator', function () {
     it('Should succeed with the correct parameters', async function () {
       this.timeout(10000)
 
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 1,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ],
-        channelId
-      }
-      const attaches = {
-        'videofile': join(__dirname, '..', 'fixtures', 'video_short.webm')
-      }
+      const fields = getCompleteVideoUploadAttributes()
+      const attaches = getVideoUploadAttaches()
 
       await makePostUploadRequest({
         url: server.url,
@@ -512,26 +392,13 @@ describe('Test videos API validator', function () {
     })
 
     it('Should fail without a valid uuid', async function () {
-      const fields = {
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
       await makePutBodyRequest({ url: server.url, path: path + 'blabla', token: server.accessToken, fields })
     })
 
     it('Should fail with an unknown id', async function () {
-      const fields = {
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+
       await makePutBodyRequest({
         url: server.url,
         path: path + '4da6fde3-88f7-4d16-b119-108df5630b06',
@@ -542,127 +409,77 @@ describe('Test videos API validator', function () {
     })
 
     it('Should fail with a long name', async function () {
-      const fields = {
-        name: 'My very very very very very very very very very very very very very very very very very  ' +
-        'very very very very very very very very very very very very very very very very long long' +
-        'very very very very very very very very very very very very very very very very long name',
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.name = 'My very very very very very very very very very very very very very very very very long'.repeat(3)
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a bad category', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 128,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.category = 128
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a bad licence', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 128,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.licence = 128
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a bad language', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 3,
-        language: 896,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.language = 896
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a bad nsfw attribute', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 5,
-        language: 6,
-        nsfw: -4,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.nsfw = (-4 as any)
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a long description', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description which is very very very very very very very very very very very very very long'.repeat(35),
-        tags: [ 'tag1', 'tag2' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.description = 'my super description which is very very very very very very very very very very very very very long'.repeat(35)
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with too many tags', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.tags = [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ]
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a tag length too low', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'tag1', 't' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.tags = [ 'tag1', 't' ]
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a tag length too big', async function () {
-      const fields = {
-        name: 'my super name',
-        category: 5,
-        licence: 2,
-        language: 6,
-        nsfw: false,
-        description: 'my super description',
-        tags: [ 'my_super_tag_too_long_long_long_long', 'tag1' ]
-      }
+      const fields = getCompleteVideoUpdateAttributes()
+      fields.tags = [ 'my_super_tag_too_long_long_long_long', 'tag1' ]
+
       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
     })
 
     it('Should fail with a video of another user')
 
     it('Should fail with a video of another pod')
+
+    it('Should succeed with the correct parameters', async function () {
+      const fields = getCompleteVideoUpdateAttributes()
+
+      await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields, statusCodeExpected: 204 })
+    })
   })
 
   describe('When getting a video', function () {
index 2ff0ecf247511240ee2c431c65708c8e78ea96a4..371f1bc439eab2c1628f3554b64d1cf657392800 100644 (file)
@@ -8,6 +8,7 @@ import './video-abuse'
 import './video-blacklist'
 import './video-blacklist-management'
 import './video-description'
+import './video-privacy'
 import './multiple-pods'
 import './services'
 import './request-schedulers'
index d3a98243648c8c3e5de8946d5875ca0597a824f9..3a05d0727755354801162f1bac7a67dc6c31fb25 100644 (file)
@@ -22,6 +22,7 @@ import {
   getVideoCategories,
   getVideoLicences,
   getVideoLanguages,
+  getVideoPrivacies,
   testVideoImage,
   webtorrentAdd,
   getVideo,
@@ -76,6 +77,15 @@ describe('Test a single pod', function () {
     expect(languages[3]).to.equal('Mandarin')
   })
 
+  it('Should list video privacies', async function () {
+    const res = await getVideoPrivacies(server.url)
+
+    const privacies = res.body
+    expect(Object.keys(privacies)).to.have.length.at.least(3)
+
+    expect(privacies[3]).to.equal('Private')
+  })
+
   it('Should not have videos', async function () {
     const res = await getVideosList(server.url)
 
@@ -482,19 +492,6 @@ describe('Test a single pod', function () {
   //   })
   // })
 
-  it('Should search the right magnetUri video', async function () {
-    const video = videosListBase[0]
-    const res = await getVideo(server.url, video.id)
-    const videoDetails = res.body
-
-    const res2 = await searchVideoWithPagination(server.url, encodeURIComponent(videoDetails.files[0].magnetUri), 'magnetUri', 0, 15)
-
-    const videos = res2.body.data
-    expect(res2.body.total).to.equal(1)
-    expect(videos.length).to.equal(1)
-    expect(videos[0].name).to.equal(video.name)
-  })
-
   it('Should list and sort by name in descending order', async function () {
     const res = await getVideosListSort(server.url, '-name')
 
index bdef62c46942b7bf5c1c0bea8a610b71281ebb3b..6f40ca3c98028f791feef2fa1de2cef3c7157043 100644 (file)
@@ -31,6 +31,7 @@ import {
   getBlacklistedVideosList
 } from '../utils'
 import { UserRole } from '../../../shared'
+import { getMyVideos } from '../utils/videos'
 
 describe('Test users', function () {
   let server: ServerInfo
@@ -197,10 +198,22 @@ describe('Test users', function () {
   it('Should be able to upload a video with this user', async function () {
     this.timeout(5000)
 
-    const videoAttributes = {}
+    const videoAttributes = {
+      name: 'super user video'
+    }
     await uploadVideo(server.url, accessTokenUser, videoAttributes)
   })
 
+  it('Should be able to list my videos', async function () {
+    const res = await getMyVideos(server.url, accessTokenUser, 0, 5)
+    expect(res.body.total).to.equal(1)
+
+    const videos = res.body.data
+    expect(videos).to.have.lengthOf(1)
+
+    expect(videos[0].name).to.equal('super user video')
+  })
+
   it('Should list all the users', async function () {
     const res = await getUsersList(server.url)
     const result = res.body
diff --git a/server/tests/api/video-privacy.ts b/server/tests/api/video-privacy.ts
new file mode 100644 (file)
index 0000000..beac161
--- /dev/null
@@ -0,0 +1,158 @@
+/* tslint:disable:no-unused-expression */
+
+import 'mocha'
+import * as chai from 'chai'
+const expect = chai.expect
+
+import {
+  ServerInfo,
+  flushTests,
+  uploadVideo,
+  makeFriends,
+  getVideosList,
+  wait,
+  setAccessTokensToServers,
+  flushAndRunMultipleServers,
+  killallServers
+} from '../utils'
+import { VideoPrivacy } from '../../../shared/models/videos/video-privacy.enum'
+import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../utils/videos'
+import { createUser } from '../utils/users'
+import { getUserAccessToken } from '../utils/login'
+
+describe('Test video privacy', function () {
+  let servers: ServerInfo[] = []
+  let privateVideoId
+  let privateVideoUUID
+  let unlistedVideoUUID
+
+  before(async function () {
+    this.timeout(120000)
+
+    // Run servers
+    servers = await flushAndRunMultipleServers(2)
+
+    // Get the access tokens
+    await setAccessTokensToServers(servers)
+
+    // Pod 1 makes friend with pod 2
+    await makeFriends(servers[0].url, servers[0].accessToken)
+  })
+
+  it('Should upload a private video on pod 1', async function () {
+    this.timeout(15000)
+
+    const attributes = {
+      privacy: VideoPrivacy.PRIVATE
+    }
+    await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
+
+    await wait(11000)
+  })
+
+  it('Should not have this private video on pod 2', async function () {
+    const res = await getVideosList(servers[1].url)
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.have.lengthOf(0)
+  })
+
+  it('Should list my (private) videos', async function () {
+    const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 1)
+
+    expect(res.body.total).to.equal(1)
+    expect(res.body.data).to.have.lengthOf(1)
+
+    privateVideoId = res.body.data[0].id
+    privateVideoUUID = res.body.data[0].uuid
+  })
+
+  it('Should not be able to watch this video with non authenticated user', async function () {
+    await getVideo(servers[0].url, privateVideoUUID, 401)
+  })
+
+  it('Should not be able to watch this private video with another user', async function () {
+    const user = {
+      username: 'hello',
+      password: 'super password'
+    }
+    await createUser(servers[0].url, servers[0].accessToken, user.username, user.password)
+
+    const token = await getUserAccessToken(servers[0], user)
+    await getVideoWithToken(servers[0].url, token, privateVideoUUID, 403)
+  })
+
+  it('Should be able to watch this video with the correct user', async function () {
+    await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID)
+  })
+
+  it('Should upload a unlisted video on pod 2', async function () {
+    this.timeout(30000)
+
+    const attributes = {
+      name: 'unlisted video',
+      privacy: VideoPrivacy.UNLISTED
+    }
+    await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
+
+    await wait(22000)
+  })
+
+  it('Should not have this unlisted video listed on pod 1 and 2', async function () {
+    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)
+    }
+  })
+
+  it('Should list my (unlisted) videos', async function () {
+    const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1)
+
+    expect(res.body.total).to.equal(1)
+    expect(res.body.data).to.have.lengthOf(1)
+
+    unlistedVideoUUID = res.body.data[0].uuid
+  })
+
+  it('Should be able to get this unlisted video', async function () {
+    for (const server of servers) {
+      const res = await getVideo(server.url, unlistedVideoUUID)
+
+      expect(res.body.name).to.equal('unlisted video')
+    }
+  })
+
+  it('Should update the private video to public on pod 1', async function () {
+    this.timeout(15000)
+
+    const attribute = {
+      name: 'super video public',
+      privacy: VideoPrivacy.PUBLIC
+    }
+
+    await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
+
+    await wait(11000)
+  })
+
+  it('Should not have this new unlisted video listed on pod 1 and 2', async function () {
+    for (const server of servers) {
+      const res = await getVideosList(server.url)
+
+      expect(res.body.total).to.equal(1)
+      expect(res.body.data).to.have.lengthOf(1)
+      expect(res.body.data[0].name).to.equal('super video public')
+    }
+  })
+
+  after(async function () {
+    killallServers(servers)
+
+    // Keep the logs if the test failed
+    if (this['ok']) {
+      await flushTests()
+    }
+  })
+})
index 2a5d00255841039e11cccb0ec1945f4972529fb1..d4d5faf0a6e78388ee48dad1a8184adceb78c319 100644 (file)
@@ -7,6 +7,7 @@ import { makeGetRequest } from './requests'
 import { readFilePromise } from './miscs'
 import { ServerInfo } from './servers'
 import { getMyUserInformation } from './users'
+import { VideoPrivacy } from '../../../shared'
 
 type VideoAttributes = {
   name?: string
@@ -17,6 +18,7 @@ type VideoAttributes = {
   description?: string
   tags?: string[]
   channelId?: number
+  privacy?: VideoPrivacy
   fixture?: string
 }
 
@@ -38,6 +40,12 @@ function getVideoLanguages (url: string) {
   return makeGetRequest(url, path)
 }
 
+function getVideoPrivacies (url: string) {
+  const path = '/api/v1/videos/privacies'
+
+  return makeGetRequest(url, path)
+}
+
 function getAllVideosListBy (url: string) {
   const path = '/api/v1/videos'
 
@@ -51,14 +59,23 @@ function getAllVideosListBy (url: string) {
           .expect('Content-Type', /json/)
 }
 
-function getVideo (url: string, id: number | string) {
+function getVideo (url: string, id: number | string, expectedStatus = 200) {
   const path = '/api/v1/videos/' + id
 
   return request(url)
           .get(path)
           .set('Accept', 'application/json')
-          .expect(200)
-          .expect('Content-Type', /json/)
+          .expect(expectedStatus)
+}
+
+function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
+  const path = '/api/v1/videos/' + id
+
+  return request(url)
+    .get(path)
+    .set('Authorization', 'Bearer ' + token)
+    .set('Accept', 'application/json')
+    .expect(expectedStatus)
 }
 
 function getVideoDescription (url: string, descriptionPath: string) {
@@ -80,6 +97,22 @@ function getVideosList (url: string) {
           .expect('Content-Type', /json/)
 }
 
+function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/users/me/videos'
+
+  const req = request(url)
+    .get(path)
+    .query({ start: start })
+    .query({ count: count })
+
+  if (sort) req.query({ sort })
+
+  return req.set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
 function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
   const path = '/api/v1/videos'
 
@@ -191,6 +224,7 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
     nsfw: true,
     description: 'my super description',
     tags: [ 'tag' ],
+    privacy: VideoPrivacy.PUBLIC,
     fixture: 'video_short.webm'
   }
   attributes = Object.assign(attributes, videoAttributesArg)
@@ -204,6 +238,7 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
               .field('licence', attributes.licence.toString())
               .field('nsfw', JSON.stringify(attributes.nsfw))
               .field('description', attributes.description)
+              .field('privacy', attributes.privacy.toString())
               .field('channelId', attributes.channelId)
 
   if (attributes.language !== undefined) {
@@ -236,6 +271,7 @@ function updateVideo (url: string, accessToken: string, id: number, attributes:
   if (attributes.nsfw) body['nsfw'] = attributes.nsfw
   if (attributes.description) body['description'] = attributes.description
   if (attributes.tags) body['tags'] = attributes.tags
+  if (attributes.privacy) body['privacy'] = attributes.privacy
 
   return request(url)
           .put(path)
@@ -274,9 +310,12 @@ export {
   getVideoDescription,
   getVideoCategories,
   getVideoLicences,
+  getVideoPrivacies,
   getVideoLanguages,
   getAllVideosListBy,
+  getMyVideos,
   getVideo,
+  getVideoWithToken,
   getVideosList,
   getVideosListPagination,
   getVideosListSort,