Add video category support
authorChocobozzz <florian.bigard@gmail.com>
Wed, 22 Mar 2017 20:15:55 +0000 (21:15 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Wed, 22 Mar 2017 20:25:24 +0000 (21:25 +0100)
28 files changed:
client/src/app/app.component.ts
client/src/app/shared/forms/form-validators/video.ts
client/src/app/videos/shared/video.model.ts
client/src/app/videos/shared/video.service.ts
client/src/app/videos/video-add/video-add.component.html
client/src/app/videos/video-add/video-add.component.ts
client/src/app/videos/video-watch/video-watch.component.html
client/src/app/videos/video-watch/video-watch.component.scss
server/controllers/api/remote/videos.js
server/controllers/api/videos.js
server/helpers/custom-validators/remote/videos.js
server/helpers/custom-validators/videos.js
server/initializers/constants.js
server/initializers/migrations/0030-video-category.js [new file with mode: 0644]
server/middlewares/validators/videos.js
server/models/video.js
server/tests/api/check-params/users.js
server/tests/api/check-params/video-abuses.js
server/tests/api/check-params/videos.js
server/tests/api/friends-advanced.js
server/tests/api/multiple-pods.js
server/tests/api/requests.js
server/tests/api/single-pod.js
server/tests/api/users.js
server/tests/api/video-abuse.js
server/tests/real-world/real-world.js
server/tests/real-world/tools/upload.js
server/tests/utils/videos.js

index 8b4b4118b302ec35444322629e219261a9b79ca7..c7310690f5db2a98f31dbf66c656d19cc44dee00 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnInit, ViewContainerRef } from '@angular/core';
 import { Router } from '@angular/router';
 
 import { AuthService } from './core';
+import { VideoService } from './videos';
 import { UserService } from './shared';
 
 @Component({
@@ -27,6 +28,7 @@ export class AppComponent implements OnInit {
     private router: Router,
     private authService: AuthService,
     private userService: UserService,
+    private videoService: VideoService,
     viewContainerRef: ViewContainerRef
   ) {}
 
@@ -35,6 +37,8 @@ export class AppComponent implements OnInit {
       // The service will automatically redirect to the login page if the token is not valid anymore
       this.userService.checkTokenValidity();
     }
+
+    this.videoService.loadVideoCategories();
   }
 
   isInAdmin() {
index b2e612c62a4d39bb7504a87a3f203f277b2d303b..d972ee44bf548c2e1a1d4cc719dccca716ad05f5 100644 (file)
@@ -8,6 +8,12 @@ export const VIDEO_NAME = {
     'maxlength': 'Video name cannot be more than 50 characters long.'
   }
 };
+export const VIDEO_CATEGORY = {
+  VALIDATORS: [ Validators.required ],
+  MESSAGES: {
+    'required': 'Video category is required.'
+  }
+};
 export const VIDEO_DESCRIPTION = {
   VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(250) ],
   MESSAGES: {
index 3eef936eba59ac6f8f00e6c9e4907a3c15b855c8..b5d96f63a45b91b27eb8b355441d4eec8c2d5234 100644 (file)
@@ -2,6 +2,7 @@ export class Video {
   author: string;
   by: string;
   createdAt: Date;
+  categoryLabel: string;
   description: string;
   duration: string;
   id: string;
@@ -31,6 +32,7 @@ export class Video {
   constructor(hash: {
     author: string,
     createdAt: string,
+    categoryLabel: string,
     description: string,
     duration: number;
     id: string,
@@ -46,6 +48,7 @@ export class Video {
   }) {
     this.author  = hash.author;
     this.createdAt = new Date(hash.createdAt);
+    this.categoryLabel = hash.categoryLabel;
     this.description = hash.description;
     this.duration = Video.createDurationString(hash.duration);
     this.id = hash.id;
index 8bb5a293309aa5e193c1e2325f4e9804c0adfb8e..debc114aaca36cee3a068276c501631439ca0d4d 100644 (file)
@@ -22,6 +22,8 @@ import { Video } from './video.model';
 export class VideoService {
   private static BASE_VIDEO_URL = '/api/v1/videos/';
 
+  videoCategories: Array<{ id: number, label: string }> = [];
+
   constructor(
     private authService: AuthService,
     private authHttp: AuthHttp,
@@ -30,6 +32,19 @@ export class VideoService {
     private restService: RestService
   ) {}
 
+  loadVideoCategories() {
+    return this.http.get(VideoService.BASE_VIDEO_URL + 'categories')
+                    .map(this.restExtractor.extractDataGet)
+                    .subscribe(data => {
+                      Object.keys(data).forEach(categoryKey => {
+                        this.videoCategories.push({
+                          id: parseInt(categoryKey),
+                          label: data[categoryKey]
+                        });
+                      });
+                    });
+  }
+
   getVideo(id: string): Observable<Video> {
     return this.http.get(VideoService.BASE_VIDEO_URL + id)
                     .map(this.restExtractor.extractDataGet)
index b6be0d78298fff8dd7a5f7a528b0a3c469bda841..c6692b21db9d5f9ec8fc996708ea849c1f86e55c 100644 (file)
     </div>
   </div>
 
+  <div class="form-group">
+    <label for="category">Category</label>
+    <select class="form-control" id="category" formControlName="category">
+      <option></option>
+      <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
+    </select>
+
+    <div *ngIf="formErrors.category" class="alert alert-danger">
+      {{ formErrors.category }}
+    </div>
+  </div>
+
   <div class="form-group">
     <label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
     <input
index cd6bb99892ca2752cff29a3ed920131f4dc377ce..2ef666e17eedb2a7ce64ed0d88232c217c30fa93 100644 (file)
@@ -6,7 +6,14 @@ import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
 import { NotificationsService } from 'angular2-notifications';
 
 import { AuthService } from '../../core';
-import { FormReactive, VIDEO_NAME, VIDEO_DESCRIPTION, VIDEO_TAGS } from '../../shared';
+import {
+  FormReactive,
+  VIDEO_NAME,
+  VIDEO_CATEGORY,
+  VIDEO_DESCRIPTION,
+  VIDEO_TAGS
+} from '../../shared';
+import { VideoService } from '../shared';
 
 @Component({
   selector: 'my-videos-add',
@@ -17,16 +24,19 @@ import { FormReactive, VIDEO_NAME, VIDEO_DESCRIPTION, VIDEO_TAGS } from '../../s
 export class VideoAddComponent extends FormReactive implements OnInit {
   tags: string[] = [];
   uploader: FileUploader;
+  videoCategories = [];
 
   error: string = null;
   form: FormGroup;
   formErrors = {
     name: '',
+    category: '',
     description: '',
     currentTag: ''
   };
   validationMessages = {
     name: VIDEO_NAME.MESSAGES,
+    category: VIDEO_CATEGORY.MESSAGES,
     description: VIDEO_DESCRIPTION.MESSAGES,
     currentTag: VIDEO_TAGS.MESSAGES
   };
@@ -40,7 +50,8 @@ export class VideoAddComponent extends FormReactive implements OnInit {
     private elementRef: ElementRef,
     private formBuilder: FormBuilder,
     private router: Router,
-    private notificationsService: NotificationsService
+    private notificationsService: NotificationsService,
+    private videoService: VideoService
   ) {
     super();
   }
@@ -56,6 +67,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
   buildForm() {
     this.form = this.formBuilder.group({
       name: [ '', VIDEO_NAME.VALIDATORS ],
+      category: [ '', VIDEO_CATEGORY.VALIDATORS ],
       description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
       currentTag: [ '', VIDEO_TAGS.VALIDATORS ]
     });
@@ -64,6 +76,8 @@ export class VideoAddComponent extends FormReactive implements OnInit {
   }
 
   ngOnInit() {
+    this.videoCategories = this.videoService.videoCategories;
+
     this.uploader = new FileUploader({
       authToken: this.authService.getRequestHeaderValue(),
       queueLimit: 1,
@@ -73,9 +87,11 @@ export class VideoAddComponent extends FormReactive implements OnInit {
 
     this.uploader.onBuildItemForm = (item, form) => {
       const name = this.form.value['name'];
+      const category = this.form.value['category'];
       const description = this.form.value['description'];
 
       form.append('name', name);
+      form.append('category', category);
       form.append('description', description);
 
       for (let i = 0; i < this.tags.length; i++) {
index 67094359e2ed9a309c505bb78b0d2296c9339be3..e754d69e51436f9aad1e84e76f511b870ae21aae 100644 (file)
     </div>
   </div>
 
+  <div id="video-category" class="row">
+    <div class="col-md-12">
+      <span id="category-label">Category:</span>
+      {{ video.categoryLabel }}
+    </div>
+  </div>
+
   <div id="video-description" class="row">
     <div class="col-md-12">
       <div id="description-label">Description</div>
index 5f322a19493bf943e4d688bcbe961d67f748f25e..799e37b5dcaf43e414e6ea64ba45ed169de57990 100644 (file)
     }
   }
 
+  #video-category {
+    margin-top: 10px;
+
+    #category-label {
+      font-weight: bold;
+    }
+  }
+
   #video-description {
-    margin-top: 15px;
+    margin-top: 10px;
 
     #description-label {
       font-weight: bold;
index cbd58e0e4d47016f3c212ce08bd109837ada0ecb..c8ef0c445045222fa6f5d90dd32457f718e28e18 100644 (file)
@@ -294,6 +294,7 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
         remoteId: videoToCreateData.remoteId,
         extname: videoToCreateData.extname,
         infoHash: videoToCreateData.infoHash,
+        category: videoToCreateData.category,
         description: videoToCreateData.description,
         authorId: author.id,
         duration: videoToCreateData.duration,
@@ -390,6 +391,7 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
       const options = { transaction: t }
 
       videoInstance.set('name', videoAttributesToUpdate.name)
+      videoInstance.set('category', videoAttributesToUpdate.category)
       videoInstance.set('description', videoAttributesToUpdate.description)
       videoInstance.set('infoHash', videoAttributesToUpdate.infoHash)
       videoInstance.set('duration', videoAttributesToUpdate.duration)
index 9acdb8fd26ff7e9f48ab9768937eb5549211af40..8c69ff4e5b9dd31ded315e5b9d35c013d20c8abf 100644 (file)
@@ -45,6 +45,8 @@ const storage = multer.diskStorage({
 
 const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
 
+router.get('/categories', listVideoCategories)
+
 router.get('/abuse',
   oAuth.authenticate,
   admin.ensureIsAdmin,
@@ -110,6 +112,10 @@ module.exports = router
 
 // ---------------------------------------------------------------------------
 
+function listVideoCategories (req, res, next) {
+  res.json(constants.VIDEO_CATEGORIES)
+}
+
 function rateVideoRetryWrapper (req, res, next) {
   const options = {
     arguments: [ req, res ],
@@ -300,6 +306,7 @@ function addVideo (req, res, videoFile, finalCallback) {
         name: videoInfos.name,
         remoteId: null,
         extname: path.extname(videoFile.filename),
+        category: videoInfos.category,
         description: videoInfos.description,
         duration: videoFile.duration,
         authorId: author.id
@@ -413,6 +420,7 @@ function updateVideo (req, res, finalCallback) {
       }
 
       if (videoInfosToUpdate.name) videoInstance.set('name', videoInfosToUpdate.name)
+      if (videoInfosToUpdate.category) videoInstance.set('category', videoInfosToUpdate.category)
       if (videoInfosToUpdate.description) videoInstance.set('description', videoInfosToUpdate.description)
 
       videoInstance.save(options).asCallback(function (err) {
index e1636e0e626b9618a8ca32816b984c6138dc8f86..701acdbfd69f617fcdada8eee8e37a9e13245f87 100644 (file)
@@ -85,6 +85,7 @@ module.exports = remoteVideosValidators
 function isCommonVideoAttributesValid (video) {
   return videosValidators.isVideoDateValid(video.createdAt) &&
          videosValidators.isVideoDateValid(video.updatedAt) &&
+         videosValidators.isVideoCategoryValid(video.category) &&
          videosValidators.isVideoDescriptionValid(video.description) &&
          videosValidators.isVideoDurationValid(video.duration) &&
          videosValidators.isVideoInfoHashValid(video.infoHash) &&
index 648c7540bf33a7b1582f0a6318f192fe12e969cf..92b36671702b381179a8a0046b900cfad9ee6397 100644 (file)
@@ -13,6 +13,7 @@ const VIDEO_EVENTS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEO_EVENT
 const videosValidators = {
   isVideoAuthorValid,
   isVideoDateValid,
+  isVideoCategoryValid,
   isVideoDescriptionValid,
   isVideoDurationValid,
   isVideoInfoHashValid,
@@ -40,6 +41,10 @@ function isVideoDateValid (value) {
   return validator.isDate(value)
 }
 
+function isVideoCategoryValid (value) {
+  return constants.VIDEO_CATEGORIES[value] !== undefined
+}
+
 function isVideoDescriptionValid (value) {
   return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
 }
index 96321b211041e91885e2b39074d31f2a6567a3df..6c5287b190aca2611dbae11a22a7d2a4b4c62326 100644 (file)
@@ -5,7 +5,7 @@ const path = require('path')
 
 // ---------------------------------------------------------------------------
 
-const LAST_MIGRATION_VERSION = 25
+const LAST_MIGRATION_VERSION = 30
 
 // ---------------------------------------------------------------------------
 
@@ -103,6 +103,27 @@ const VIDEO_RATE_TYPES = {
   DISLIKE: 'dislike'
 }
 
+const VIDEO_CATEGORIES = {
+  1: 'Music',
+  2: 'Films',
+  3: 'Vehicles',
+  4: 'Art',
+  5: 'Sports',
+  6: 'Travels',
+  7: 'Gaming',
+  8: 'People',
+  9: 'Comedy',
+  10: 'Entertainment',
+  11: 'News',
+  12: 'Howto',
+  13: 'Education',
+  14: 'Activism',
+  15: 'Science & Technology',
+  16: 'Animals',
+  17: 'Kids',
+  18: 'Food'
+}
+
 // ---------------------------------------------------------------------------
 
 // Score a pod has when we create it as a friend
@@ -258,6 +279,7 @@ module.exports = {
   STATIC_PATHS,
   THUMBNAILS_SIZE,
   USER_ROLES,
+  VIDEO_CATEGORIES,
   VIDEO_RATE_TYPES
 }
 
diff --git a/server/initializers/migrations/0030-video-category.js b/server/initializers/migrations/0030-video-category.js
new file mode 100644 (file)
index 0000000..ada95b2
--- /dev/null
@@ -0,0 +1,34 @@
+'use strict'
+
+const waterfall = require('async/waterfall')
+
+// utils = { transaction, queryInterface, sequelize, Sequelize }
+exports.up = function (utils, finalCallback) {
+  const q = utils.queryInterface
+  const Sequelize = utils.Sequelize
+
+  const data = {
+    type: Sequelize.INTEGER,
+    allowNull: false,
+    defaultValue: 0
+  }
+
+  waterfall([
+
+    function addCategoryColumn (callback) {
+      q.addColumn('Videos', 'category', data, { transaction: utils.transaction }).asCallback(function (err) {
+        return callback(err)
+      })
+    },
+
+    function nullOnDefault (callback) {
+      data.defaultValue = null
+
+      q.changeColumn('Videos', 'category', data, { transaction: utils.transaction }).asCallback(callback)
+    }
+  ], finalCallback)
+}
+
+exports.down = function (options, callback) {
+  throw new Error('Not implemented.')
+}
index 7dc79c56fe1384ab811e96033927cd985a6d488c..37cc1337298ce696a6067f5c42bd9ff5ab5d4fb1 100644 (file)
@@ -21,6 +21,7 @@ const validatorsVideos = {
 function videosAdd (req, res, next) {
   req.checkBody('videofile', 'Should have a valid file').isVideoFile(req.files)
   req.checkBody('name', 'Should have a valid name').isVideoNameValid()
+  req.checkBody('category', 'Should have a valid category').isVideoCategoryValid()
   req.checkBody('description', 'Should have a valid description').isVideoDescriptionValid()
   req.checkBody('tags', 'Should have correct tags').isVideoTagsValid()
 
@@ -47,6 +48,7 @@ function videosAdd (req, res, next) {
 function videosUpdate (req, res, next) {
   req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
   req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid()
+  req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid()
   req.checkBody('description', 'Should have a valid description').optional().isVideoDescriptionValid()
   req.checkBody('tags', 'Should have correct tags').optional().isVideoTagsValid()
 
index 182555c85a41f4794393f1b1dc97a184d7923ebb..c4c7b5de84b4fc1b7e220d3869a8d17489a61901 100644 (file)
@@ -51,6 +51,16 @@ module.exports = function (sequelize, DataTypes) {
           isUUID: 4
         }
       },
+      category: {
+        type: DataTypes.INTEGER,
+        allowNull: false,
+        validate: {
+          categoryValid: function (value) {
+            const res = customVideosValidators.isVideoCategoryValid(value)
+            if (res === false) throw new Error('Video category is not valid.')
+          }
+        }
+      },
       description: {
         type: DataTypes.STRING,
         allowNull: false,
@@ -360,9 +370,15 @@ function toFormatedJSON () {
     podHost = constants.CONFIG.WEBSERVER.HOST
   }
 
+  // Maybe our pod is not up to date and there are new categories since our version
+  let categoryLabel = constants.VIDEO_CATEGORIES[this.category]
+  if (!categoryLabel) categoryLabel = 'Misc'
+
   const json = {
     id: this.id,
     name: this.name,
+    category: this.category,
+    categoryLabel,
     description: this.description,
     podHost,
     isLocal: this.isOwned(),
@@ -394,6 +410,7 @@ function toAddRemoteJSON (callback) {
 
     const remoteVideo = {
       name: self.name,
+      category: self.category,
       description: self.description,
       infoHash: self.infoHash,
       remoteId: self.id,
@@ -416,6 +433,7 @@ function toAddRemoteJSON (callback) {
 function toUpdateRemoteJSON (callback) {
   const json = {
     name: this.name,
+    category: this.category,
     description: this.description,
     infoHash: this.infoHash,
     remoteId: this.id,
index 11e2bada4da357918cfe171d139842811d4eeb21..f6fbcf555044d1b6a783eb8e3a5aa2d5ede7685b 100644 (file)
@@ -51,10 +51,11 @@ describe('Test users API validators', function () {
       },
       function (next) {
         const name = 'my super name for pod'
+        const category = 5
         const description = 'my super description for pod'
         const tags = [ 'tag' ]
         const file = 'video_short2.webm'
-        videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, file, next)
+        videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, file, next)
       },
       function (next) {
         videosUtils.getVideosList(server.url, function (err, res) {
index 7308637e29ee2312a566a3d9ebd304654d667b3c..061b80be830cb5b81850b76f8f85bd77d31cebae 100644 (file)
@@ -62,10 +62,11 @@ describe('Test video abuses API validators', function () {
       // Upload some videos on each pods
       function (next) {
         const name = 'my super name for pod'
+        const category = 2
         const description = 'my super description for pod'
         const tags = [ 'tag' ]
         const file = 'video_short2.webm'
-        videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, file, next)
+        videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, file, next)
       },
       function (next) {
         videosUtils.getVideosList(server.url, function (err, res) {
index 0f5f40b8e4efd6d77132eb1a6eece20534954d71..fbfe6f137ab66d751a86392f48653e156cb6b89f 100644 (file)
@@ -112,6 +112,7 @@ describe('Test videos API validator', function () {
 
     it('Should fail without name', function (done) {
       const data = {
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -124,6 +125,32 @@ describe('Test videos API validator', function () {
     it('Should fail with a long name', function (done) {
       const data = {
         name: 'My very very very very very very very very very very very very very very very very long name',
+        category: 5,
+        description: 'my super description',
+        tags: [ 'tag1', 'tag2' ]
+      }
+      const attach = {
+        'videofile': pathUtils.join(__dirname, '..', 'fixtures', 'video_short.webm')
+      }
+      requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
+    })
+
+    it('Should fail without a category', function (done) {
+      const data = {
+        name: 'my super name',
+        description: 'my super description',
+        tags: [ 'tag1', 'tag2' ]
+      }
+      const attach = {
+        'videofile': pathUtils.join(__dirname, '..', 'fixtures', 'video_short.webm')
+      }
+      requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
+    })
+
+    it('Should fail with a bad category', function (done) {
+      const data = {
+        name: 'my super name',
+        category: 125,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -136,6 +163,7 @@ describe('Test videos API validator', function () {
     it('Should fail without description', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         tags: [ 'tag1', 'tag2' ]
       }
       const attach = {
@@ -147,6 +175,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a long description', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description which is 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 very very' +
                      'very very very very very very very very very very very very very very very long',
@@ -161,6 +190,7 @@ describe('Test videos API validator', function () {
     it('Should fail without tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description'
       }
       const attach = {
@@ -172,6 +202,7 @@ describe('Test videos API validator', function () {
     it('Should fail with too many tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ]
       }
@@ -184,6 +215,7 @@ describe('Test videos API validator', function () {
     it('Should fail with not enough tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ ]
       }
@@ -196,6 +228,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a tag length too low', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 't' ]
       }
@@ -208,6 +241,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a tag length too big', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'mysupertagtoolong', 'tag1' ]
       }
@@ -220,6 +254,7 @@ describe('Test videos API validator', function () {
     it('Should fail with malformed tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'my tag' ]
       }
@@ -232,6 +267,7 @@ describe('Test videos API validator', function () {
     it('Should fail without an input file', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -242,6 +278,7 @@ describe('Test videos API validator', function () {
     it('Should fail without an incorrect input file', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -254,6 +291,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a too big duration', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -266,6 +304,7 @@ describe('Test videos API validator', function () {
     it('Should succeed with the correct parameters', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -302,6 +341,7 @@ describe('Test videos API validator', function () {
 
     it('Should fail without a valid uuid', function (done) {
       const data = {
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -310,6 +350,7 @@ describe('Test videos API validator', function () {
 
     it('Should fail with an unknown id', function (done) {
       const data = {
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -319,6 +360,17 @@ describe('Test videos API validator', function () {
     it('Should fail with a long name', function (done) {
       const data = {
         name: 'My very very very very very very very very very very very very very very very very long name',
+        category: 5,
+        description: 'my super description',
+        tags: [ 'tag1', 'tag2' ]
+      }
+      requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done)
+    })
+
+    it('Should fail with a bad category', function (done) {
+      const data = {
+        name: 'my super name',
+        category: 128,
         description: 'my super description',
         tags: [ 'tag1', 'tag2' ]
       }
@@ -328,6 +380,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a long description', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description which is 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 very very' +
                      'very very very very very very very very very very very very very very very long',
@@ -339,6 +392,7 @@ describe('Test videos API validator', function () {
     it('Should fail with too many tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ]
       }
@@ -348,6 +402,7 @@ describe('Test videos API validator', function () {
     it('Should fail with not enough tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ ]
       }
@@ -357,6 +412,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a tag length too low', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'tag1', 't' ]
       }
@@ -366,6 +422,7 @@ describe('Test videos API validator', function () {
     it('Should fail with a tag length too big', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'mysupertagtoolong', 'tag1' ]
       }
@@ -375,6 +432,7 @@ describe('Test videos API validator', function () {
     it('Should fail with malformed tags', function (done) {
       const data = {
         name: 'my super name',
+        category: 5,
         description: 'my super description',
         tags: [ 'my tag' ]
       }
index 15ca1a37c1f161c698fcbd0d22f414caee420ed3..584c38c245b94651bc499d004d0e85bbef4e0591 100644 (file)
@@ -32,12 +32,13 @@ describe('Test advanced friends', function () {
 
   function uploadVideo (podNumber, callback) {
     const name = 'my super video'
+    const category = 5
     const description = 'my super description'
     const tags = [ 'tag1', 'tag2' ]
     const fixture = 'video_short.webm'
     const server = servers[podNumber - 1]
 
-    return videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, fixture, callback)
+    return videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, fixture, callback)
   }
 
   function getVideos (podNumber, callback) {
index 552f10c6fe75356a57be38d8d1e0cb6594e80df5..eccc9ecef6494de6e3907562b12b870496212300 100644 (file)
@@ -81,10 +81,11 @@ describe('Test multiple pods', function () {
       series([
         function (next) {
           const name = 'my super name for pod 1'
+          const category = 5
           const description = 'my super description for pod 1'
           const tags = [ 'tag1p1', 'tag2p1' ]
           const file = 'video_short1.webm'
-          videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, description, tags, file, next)
+          videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, category, description, tags, file, next)
         },
         function (next) {
           setTimeout(next, 11000)
@@ -104,6 +105,8 @@ describe('Test multiple pods', function () {
               expect(videos.length).to.equal(1)
               const video = videos[0]
               expect(video.name).to.equal('my super name for pod 1')
+              expect(video.category).to.equal(5)
+              expect(video.categoryLabel).to.equal('Sports')
               expect(video.description).to.equal('my super description for pod 1')
               expect(video.podHost).to.equal('localhost:9001')
               expect(video.magnetUri).to.exist
@@ -144,10 +147,11 @@ describe('Test multiple pods', function () {
       series([
         function (next) {
           const name = 'my super name for pod 2'
+          const category = 4
           const description = 'my super description for pod 2'
           const tags = [ 'tag1p2', 'tag2p2', 'tag3p2' ]
           const file = 'video_short2.webm'
-          videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, description, tags, file, next)
+          videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, category, description, tags, file, next)
         },
         function (next) {
           setTimeout(next, 11000)
@@ -167,6 +171,8 @@ describe('Test multiple pods', function () {
               expect(videos.length).to.equal(2)
               const video = videos[1]
               expect(video.name).to.equal('my super name for pod 2')
+              expect(video.category).to.equal(4)
+              expect(video.categoryLabel).to.equal('Art')
               expect(video.description).to.equal('my super description for pod 2')
               expect(video.podHost).to.equal('localhost:9002')
               expect(video.magnetUri).to.exist
@@ -207,17 +213,19 @@ describe('Test multiple pods', function () {
       series([
         function (next) {
           const name = 'my super name for pod 3'
+          const category = 6
           const description = 'my super description for pod 3'
           const tags = [ 'tag1p3' ]
           const file = 'video_short3.webm'
-          videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next)
+          videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, category, description, tags, file, next)
         },
         function (next) {
           const name = 'my super name for pod 3-2'
+          const category = 7
           const description = 'my super description for pod 3-2'
           const tags = [ 'tag2p3', 'tag3p3', 'tag4p3' ]
           const file = 'video_short.webm'
-          videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next)
+          videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, category, description, tags, file, next)
         },
         function (next) {
           setTimeout(next, 22000)
@@ -247,6 +255,8 @@ describe('Test multiple pods', function () {
               }
 
               expect(video1.name).to.equal('my super name for pod 3')
+              expect(video1.category).to.equal(6)
+              expect(video1.categoryLabel).to.equal('Travels')
               expect(video1.description).to.equal('my super description for pod 3')
               expect(video1.podHost).to.equal('localhost:9003')
               expect(video1.magnetUri).to.exist
@@ -257,6 +267,8 @@ describe('Test multiple pods', function () {
               expect(miscsUtils.dateIsValid(video1.updatedAt)).to.be.true
 
               expect(video2.name).to.equal('my super name for pod 3-2')
+              expect(video2.category).to.equal(7)
+              expect(video2.categoryLabel).to.equal('Gaming')
               expect(video2.description).to.equal('my super description for pod 3-2')
               expect(video2.podHost).to.equal('localhost:9003')
               expect(video2.magnetUri).to.exist
@@ -603,10 +615,11 @@ describe('Test multiple pods', function () {
       this.timeout(15000)
 
       const name = 'my super video updated'
+      const category = 10
       const description = 'my super description updated'
       const tags = [ 'tagup1', 'tagup2' ]
 
-      videosUtils.updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, name, description, tags, function (err) {
+      videosUtils.updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, name, category, description, tags, function (err) {
         if (err) throw err
 
         setTimeout(done, 11000)
@@ -629,6 +642,8 @@ describe('Test multiple pods', function () {
           })
 
           expect(!!videoUpdated).to.be.true
+          expect(videoUpdated.category).to.equal(10)
+          expect(videoUpdated.categoryLabel).to.equal('Entertainment')
           expect(videoUpdated.description).to.equal('my super description updated')
           expect(videoUpdated.tags).to.deep.equal([ 'tagup1', 'tagup2' ])
           expect(miscsUtils.dateIsValid(videoUpdated.updatedAt, 20000)).to.be.true
index 215c2a8f3ac4521257a88945f6edcfb3aea84ae2..b4b8393e355213b81cfee26b47c09e7568b611f9 100644 (file)
@@ -18,11 +18,12 @@ describe('Test requests stats', function () {
 
   function uploadVideo (server, callback) {
     const name = 'my super video'
+    const category = 5
     const description = 'my super description'
     const tags = [ 'tag1', 'tag2' ]
     const fixture = 'video_short.webm'
 
-    videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, fixture, callback)
+    videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, fixture, callback)
   }
 
   function getRequestsStats (server, callback) {
index 96e4aff9e7191faa4476d4f5daa0244615c5fb71..d583592d8755583f1b05ee00914ffccfd1610dbf 100644 (file)
@@ -44,6 +44,19 @@ describe('Test a single pod', function () {
     ], done)
   })
 
+  it('Should list video categories', function (done) {
+    videosUtils.getVideoCategories(server.url, function (err, res) {
+      if (err) throw err
+
+      const categories = res.body
+      expect(Object.keys(categories)).to.have.length.above(10)
+
+      expect(categories[11]).to.equal('News')
+
+      done()
+    })
+  })
+
   it('Should not have videos', function (done) {
     videosUtils.getVideosList(server.url, function (err, res) {
       if (err) throw err
@@ -60,9 +73,10 @@ describe('Test a single pod', function () {
     this.timeout(5000)
     const name = 'my super name'
     const description = 'my super description'
+    const category = 2
     const tags = [ 'tag1', 'tag2', 'tag3' ]
     const file = 'video_short.webm'
-    videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, file, done)
+    videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, file, done)
   })
 
   it('Should seed the uploaded video', function (done) {
@@ -78,6 +92,8 @@ describe('Test a single pod', function () {
 
       const video = res.body.data[0]
       expect(video.name).to.equal('my super name')
+      expect(video.category).to.equal(2)
+      expect(video.categoryLabel).to.equal('Films')
       expect(video.description).to.equal('my super description')
       expect(video.podHost).to.equal('localhost:9001')
       expect(video.magnetUri).to.exist
@@ -113,6 +129,8 @@ describe('Test a single pod', function () {
 
       const video = res.body
       expect(video.name).to.equal('my super name')
+      expect(video.category).to.equal(2)
+      expect(video.categoryLabel).to.equal('Films')
       expect(video.description).to.equal('my super description')
       expect(video.podHost).to.equal('localhost:9001')
       expect(video.magnetUri).to.exist
@@ -152,6 +170,8 @@ describe('Test a single pod', function () {
 
       const video = res.body.data[0]
       expect(video.name).to.equal('my super name')
+      expect(video.category).to.equal(2)
+      expect(video.categoryLabel).to.equal('Films')
       expect(video.description).to.equal('my super description')
       expect(video.podHost).to.equal('localhost:9001')
       expect(video.author).to.equal('root')
@@ -207,6 +227,8 @@ describe('Test a single pod', function () {
 
       const video = res.body.data[0]
       expect(video.name).to.equal('my super name')
+      expect(video.category).to.equal(2)
+      expect(video.categoryLabel).to.equal('Films')
       expect(video.description).to.equal('my super description')
       expect(video.podHost).to.equal('localhost:9001')
       expect(video.author).to.equal('root')
@@ -301,9 +323,10 @@ describe('Test a single pod', function () {
     each(videos, function (video, callbackEach) {
       const name = video + ' name'
       const description = video + ' description'
+      const category = 2
       const tags = [ 'tag1', 'tag2', 'tag3' ]
 
-      videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, video, callbackEach)
+      videosUtils.uploadVideo(server.url, server.accessToken, name, category, description, tags, video, callbackEach)
     }, done)
   })
 
@@ -468,7 +491,7 @@ describe('Test a single pod', function () {
   //   })
   // })
 
-  it('Should search the good magnetUri video', function (done) {
+  it('Should search the right magnetUri video', function (done) {
     const video = videosListBase[0]
     videosUtils.searchVideoWithPagination(server.url, encodeURIComponent(video.magnetUri), 'magnetUri', 0, 15, function (err, res) {
       if (err) throw err
@@ -521,10 +544,11 @@ describe('Test a single pod', function () {
 
   it('Should update a video', function (done) {
     const name = 'my super video updated'
+    const category = 4
     const description = 'my super description updated'
     const tags = [ 'tagup1', 'tagup2' ]
 
-    videosUtils.updateVideo(server.url, server.accessToken, videoId, name, description, tags, done)
+    videosUtils.updateVideo(server.url, server.accessToken, videoId, name, category, description, tags, done)
   })
 
   it('Should have the video updated', function (done) {
@@ -536,6 +560,8 @@ describe('Test a single pod', function () {
       const video = res.body
 
       expect(video.name).to.equal('my super video updated')
+      expect(video.category).to.equal(4)
+      expect(video.categoryLabel).to.equal('Art')
       expect(video.description).to.equal('my super description updated')
       expect(video.podHost).to.equal('localhost:9001')
       expect(video.author).to.equal('root')
@@ -562,7 +588,7 @@ describe('Test a single pod', function () {
   it('Should update only the tags of a video', function (done) {
     const tags = [ 'tag1', 'tag2', 'supertag' ]
 
-    videosUtils.updateVideo(server.url, server.accessToken, videoId, null, null, tags, function (err) {
+    videosUtils.updateVideo(server.url, server.accessToken, videoId, null, null, null, tags, function (err) {
       if (err) throw err
 
       videosUtils.getVideo(server.url, videoId, function (err, res) {
@@ -571,6 +597,8 @@ describe('Test a single pod', function () {
         const video = res.body
 
         expect(video.name).to.equal('my super video updated')
+        expect(video.category).to.equal(4)
+        expect(video.categoryLabel).to.equal('Art')
         expect(video.description).to.equal('my super description updated')
         expect(video.podHost).to.equal('localhost:9001')
         expect(video.author).to.equal('root')
@@ -587,7 +615,7 @@ describe('Test a single pod', function () {
   it('Should update only the description of a video', function (done) {
     const description = 'hello everybody'
 
-    videosUtils.updateVideo(server.url, server.accessToken, videoId, null, description, null, function (err) {
+    videosUtils.updateVideo(server.url, server.accessToken, videoId, null, null, description, null, function (err) {
       if (err) throw err
 
       videosUtils.getVideo(server.url, videoId, function (err, res) {
@@ -596,6 +624,8 @@ describe('Test a single pod', function () {
         const video = res.body
 
         expect(video.name).to.equal('my super video updated')
+        expect(video.category).to.equal(4)
+        expect(video.categoryLabel).to.equal('Art')
         expect(video.description).to.equal('hello everybody')
         expect(video.podHost).to.equal('localhost:9001')
         expect(video.author).to.equal('root')
index f9568b874b533d1b438dca7caaf9ec040b5d009b..0f062c11f85b72754741d129f88640d0384dcc28 100644 (file)
@@ -87,9 +87,10 @@ describe('Test users', function () {
 
     const name = 'my super name'
     const description = 'my super description'
+    const category = 5
     const tags = [ 'tag1', 'tag2' ]
     const video = 'video_short.webm'
-    videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 401, done)
+    videosUtils.uploadVideo(server.url, accessToken, name, category, description, tags, video, 401, done)
   })
 
   it('Should not be able to make friends', function (done) {
@@ -113,10 +114,11 @@ describe('Test users', function () {
 
   it('Should upload the video with the correct token', function (done) {
     const name = 'my super name'
+    const category = 5
     const description = 'my super description'
     const tags = [ 'tag1', 'tag2' ]
     const video = 'video_short.webm'
-    videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, function (err, res) {
+    videosUtils.uploadVideo(server.url, accessToken, name, category, description, tags, video, 204, function (err, res) {
       if (err) throw err
 
       videosUtils.getVideosList(server.url, function (err, res) {
@@ -133,10 +135,11 @@ describe('Test users', function () {
 
   it('Should upload the video again with the correct token', function (done) {
     const name = 'my super name 2'
+    const category = 5
     const description = 'my super description 2'
     const tags = [ 'tag1' ]
     const video = 'video_short.webm'
-    videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, done)
+    videosUtils.uploadVideo(server.url, accessToken, name, category, description, tags, video, 204, done)
   })
 
   it('Should retrieve a video rating', function (done) {
@@ -228,10 +231,11 @@ describe('Test users', function () {
     this.timeout(5000)
 
     const name = 'my super name'
+    const category = 5
     const description = 'my super description'
     const tags = [ 'tag1', 'tag2', 'tag3' ]
     const file = 'video_short.webm'
-    videosUtils.uploadVideo(server.url, accessTokenUser, name, description, tags, file, done)
+    videosUtils.uploadVideo(server.url, accessTokenUser, name, category, description, tags, file, done)
   })
 
   it('Should list all the users', function (done) {
index 0c43418604b30c1ac67582ad3f7707ecd2f4a15f..871054788dec75f121f0671389c18d94867a5af4 100644 (file)
@@ -46,17 +46,19 @@ describe('Test video abuses', function () {
       // Upload some videos on each pods
       function (next) {
         const name = 'my super name for pod 1'
+        const category = 5
         const description = 'my super description for pod 1'
         const tags = [ 'tag' ]
         const file = 'video_short2.webm'
-        videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, description, tags, file, next)
+        videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, category, description, tags, file, next)
       },
       function (next) {
         const name = 'my super name for pod 2'
+        const category = 5
         const description = 'my super description for pod 2'
         const tags = [ 'tag' ]
         const file = 'video_short2.webm'
-        videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, description, tags, file, next)
+        videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, category, description, tags, file, next)
       },
       // Wait videos propagation
       function (next) {
index 239b790ae0d0bab87a063f1e19a5af8047271b04..f17c83f8590604e3b9c3c267d061806cc9cc1ada 100644 (file)
@@ -201,13 +201,14 @@ function upload (servers, numServer, callback) {
   if (!callback) callback = function () {}
 
   const name = Date.now() + ' name'
+  const category = 4
   const description = Date.now() + ' description'
   const tags = [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ]
   const file = 'video_short1.webm'
 
   console.log('Uploading video to server ' + numServer)
 
-  videosUtils.uploadVideo(servers[numServer].url, servers[numServer].accessToken, name, description, tags, file, callback)
+  videosUtils.uploadVideo(servers[numServer].url, servers[numServer].accessToken, name, category, description, tags, file, callback)
 }
 
 function update (servers, numServer, callback) {
index ba08028cf6fd1f2c161a223e7a4b6e691b0a0e21..49076ee2ad809df6c4e1b5e49815e78d781db3cc 100644 (file)
@@ -9,6 +9,7 @@ program
   .option('-u, --url <url>', 'Server url')
   .option('-a, --access-token <token>', 'Access token')
   .option('-n, --name <name>', 'Video name')
+  .option('-d, --category <category number>', 'Category number')
   .option('-d, --description <description>', 'Video description')
   .option('-t, --tags <tags>', 'Video tags', list)
   .option('-f, --file <file>', 'Video absolute file path')
@@ -18,6 +19,7 @@ if (
   !program.url ||
   !program.accessToken ||
   !program.name ||
+  !program.category ||
   !program.description ||
   !program.tags ||
   !Array.isArray(program.tags) ||
@@ -34,6 +36,7 @@ fs.access(program.file, fs.F_OK, function (err) {
     program.url,
     program.accessToken,
     program.name,
+    program.category,
     program.description,
     program.tags,
     program.file
@@ -46,10 +49,10 @@ function list (val) {
   return val.split(',')
 }
 
-function upload (url, accessToken, name, description, tags, file) {
+function upload (url, accessToken, name, category, description, tags, file) {
   console.log('Uploading %s video...', program.name)
 
-  utils.uploadVideo(url, accessToken, name, description, tags, file, function (err) {
+  utils.uploadVideo(url, accessToken, name, category, description, tags, file, function (err) {
     if (err) throw err
 
     console.log('Video uploaded.')
index 1774260761cfa55549a61497ddba6c9311b261e1..0aa6ec5a8074963b1f50904fd7b2ede57017a37f 100644 (file)
@@ -5,6 +5,7 @@ const pathUtils = require('path')
 const request = require('supertest')
 
 const videosUtils = {
+  getVideoCategories,
   getAllVideosListBy,
   getVideo,
   getVideosList,
@@ -22,6 +23,17 @@ const videosUtils = {
 
 // ---------------------- Export functions --------------------
 
+function getVideoCategories (url, end) {
+  const path = '/api/v1/videos/categories'
+
+  request(url)
+    .get(path)
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+    .end(end)
+}
+
 function getAllVideosListBy (url, end) {
   const path = '/api/v1/videos'
 
@@ -181,7 +193,7 @@ function testVideoImage (url, videoName, imagePath, callback) {
   }
 }
 
-function uploadVideo (url, accessToken, name, description, tags, fixture, specialStatus, end) {
+function uploadVideo (url, accessToken, name, category, description, tags, fixture, specialStatus, end) {
   if (!end) {
     end = specialStatus
     specialStatus = 204
@@ -194,6 +206,7 @@ function uploadVideo (url, accessToken, name, description, tags, fixture, specia
               .set('Accept', 'application/json')
               .set('Authorization', 'Bearer ' + accessToken)
               .field('name', name)
+              .field('category', category)
               .field('description', description)
 
   for (let i = 0; i < tags.length; i++) {
@@ -212,7 +225,7 @@ function uploadVideo (url, accessToken, name, description, tags, fixture, specia
      .end(end)
 }
 
-function updateVideo (url, accessToken, id, name, description, tags, specialStatus, end) {
+function updateVideo (url, accessToken, id, name, category, description, tags, specialStatus, end) {
   if (!end) {
     end = specialStatus
     specialStatus = 204
@@ -226,6 +239,7 @@ function updateVideo (url, accessToken, id, name, description, tags, specialStat
               .set('Authorization', 'Bearer ' + accessToken)
 
   if (name) req.field('name', name)
+  if (category) req.field('category', category)
   if (description) req.field('description', description)
 
   if (tags) {