diff options
-rw-r--r-- | client/.bootstraprc | 4 | ||||
-rw-r--r-- | client/config/webpack.common.js | 8 | ||||
-rw-r--r-- | client/package.json | 6 | ||||
-rw-r--r-- | client/src/app/shared/search/search-field.type.ts | 2 | ||||
-rw-r--r-- | client/src/app/shared/search/search.component.ts | 3 | ||||
-rw-r--r-- | client/src/app/shared/users/auth.service.ts | 6 | ||||
-rw-r--r-- | client/src/app/videos/video-add/video-add.component.html | 64 | ||||
-rw-r--r-- | client/src/app/videos/video-add/video-add.component.scss | 27 | ||||
-rw-r--r-- | client/src/app/videos/video-add/video-add.component.ts | 162 | ||||
-rw-r--r-- | client/src/vendor.ts | 4 | ||||
-rw-r--r-- | client/tsconfig.json | 2 | ||||
-rw-r--r-- | client/typings.json | 2 | ||||
-rw-r--r-- | server/initializers/constants.js | 4 | ||||
-rw-r--r-- | server/middlewares/reqValidators/videos.js | 2 | ||||
-rw-r--r-- | server/models/videos.js | 1 |
15 files changed, 201 insertions, 96 deletions
diff --git a/client/.bootstraprc b/client/.bootstraprc index 76a0bdb7b..dd6c2128c 100644 --- a/client/.bootstraprc +++ b/client/.bootstraprc | |||
@@ -86,7 +86,7 @@ styles: | |||
86 | breadcrumbs: false | 86 | breadcrumbs: false |
87 | pagination: true | 87 | pagination: true |
88 | pager: false | 88 | pager: false |
89 | labels: false | 89 | labels: true |
90 | badges: false | 90 | badges: false |
91 | jumbotron: false | 91 | jumbotron: false |
92 | thumbnails: true | 92 | thumbnails: true |
@@ -112,7 +112,7 @@ styles: | |||
112 | ### Bootstrap scripts | 112 | ### Bootstrap scripts |
113 | scripts: | 113 | scripts: |
114 | transition: false | 114 | transition: false |
115 | alert: true | 115 | alert: false |
116 | button: false | 116 | button: false |
117 | carousel: false | 117 | carousel: false |
118 | collapse: false | 118 | collapse: false |
diff --git a/client/config/webpack.common.js b/client/config/webpack.common.js index 7f1da74b9..9d05668e2 100644 --- a/client/config/webpack.common.js +++ b/client/config/webpack.common.js | |||
@@ -68,7 +68,7 @@ module.exports = { | |||
68 | root: helpers.root('src'), | 68 | root: helpers.root('src'), |
69 | 69 | ||
70 | // remove other default values | 70 | // remove other default values |
71 | modulesDirectories: [ 'node_modules', 'node_modules/blueimp-file-upload/js/vendor' ], | 71 | modulesDirectories: [ 'node_modules' ], |
72 | 72 | ||
73 | packageAlias: 'browser' | 73 | packageAlias: 'browser' |
74 | 74 | ||
@@ -246,12 +246,6 @@ module.exports = { | |||
246 | chunksSortMode: 'dependency' | 246 | chunksSortMode: 'dependency' |
247 | }), | 247 | }), |
248 | 248 | ||
249 | new webpack.ProvidePlugin({ | ||
250 | jQuery: 'jquery', | ||
251 | $: 'jquery', | ||
252 | jquery: 'jquery' | ||
253 | }) | ||
254 | |||
255 | ], | 249 | ], |
256 | 250 | ||
257 | /* | 251 | /* |
diff --git a/client/package.json b/client/package.json index d2d039437..cd8afcc98 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -28,7 +28,6 @@ | |||
28 | "@angular/router-deprecated": "2.0.0-rc.1", | 28 | "@angular/router-deprecated": "2.0.0-rc.1", |
29 | "angular-pipes": "^2.0.0", | 29 | "angular-pipes": "^2.0.0", |
30 | "awesome-typescript-loader": "^0.17.0", | 30 | "awesome-typescript-loader": "^0.17.0", |
31 | "blueimp-file-upload": "^9.12.1", | ||
32 | "bootstrap-loader": "^1.0.8", | 31 | "bootstrap-loader": "^1.0.8", |
33 | "bootstrap-sass": "^3.3.6", | 32 | "bootstrap-sass": "^3.3.6", |
34 | "compression-webpack-plugin": "^0.3.1", | 33 | "compression-webpack-plugin": "^0.3.1", |
@@ -40,10 +39,9 @@ | |||
40 | "es6-shim": "^0.35.0", | 39 | "es6-shim": "^0.35.0", |
41 | "file-loader": "^0.8.5", | 40 | "file-loader": "^0.8.5", |
42 | "html-webpack-plugin": "^2.19.0", | 41 | "html-webpack-plugin": "^2.19.0", |
43 | "jquery": "^2.2.3", | ||
44 | "jquery.ui.widget": "^1.10.3", | ||
45 | "json-loader": "^0.5.4", | 42 | "json-loader": "^0.5.4", |
46 | "ng2-bootstrap": "^1.0.16", | 43 | "ng2-bootstrap": "^1.0.16", |
44 | "ng2-file-upload": "^1.0.3", | ||
47 | "node-sass": "^3.7.0", | 45 | "node-sass": "^3.7.0", |
48 | "normalize.css": "^4.1.1", | 46 | "normalize.css": "^4.1.1", |
49 | "raw-loader": "^0.5.1", | 47 | "raw-loader": "^0.5.1", |
@@ -75,4 +73,4 @@ | |||
75 | "bundles/" | 73 | "bundles/" |
76 | ] | 74 | ] |
77 | } | 75 | } |
78 | } \ No newline at end of file | 76 | } |
diff --git a/client/src/app/shared/search/search-field.type.ts b/client/src/app/shared/search/search-field.type.ts index 846236290..5228ee68a 100644 --- a/client/src/app/shared/search/search-field.type.ts +++ b/client/src/app/shared/search/search-field.type.ts | |||
@@ -1 +1 @@ | |||
export type SearchField = "name" | "author" | "podUrl" | "magnetUri"; | export type SearchField = "name" | "author" | "podUrl" | "magnetUri" | "tags"; | ||
diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts index 31f8b1535..c14c2d99c 100644 --- a/client/src/app/shared/search/search.component.ts +++ b/client/src/app/shared/search/search.component.ts | |||
@@ -18,7 +18,8 @@ export class SearchComponent { | |||
18 | name: 'Name', | 18 | name: 'Name', |
19 | author: 'Author', | 19 | author: 'Author', |
20 | podUrl: 'Pod Url', | 20 | podUrl: 'Pod Url', |
21 | magnetUri: 'Magnet Uri' | 21 | magnetUri: 'Magnet Uri', |
22 | tags: 'Tags' | ||
22 | }; | 23 | }; |
23 | searchCriterias: Search = { | 24 | searchCriterias: Search = { |
24 | field: 'name', | 25 | field: 'name', |
diff --git a/client/src/app/shared/users/auth.service.ts b/client/src/app/shared/users/auth.service.ts index 720037563..1c822c1e1 100644 --- a/client/src/app/shared/users/auth.service.ts +++ b/client/src/app/shared/users/auth.service.ts | |||
@@ -43,7 +43,11 @@ export class AuthService { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | getRequestHeader() { | 45 | getRequestHeader() { |
46 | return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` }); | 46 | return new Headers({ 'Authorization': this.getRequestHeaderValue() }); |
47 | } | ||
48 | |||
49 | getRequestHeaderValue() { | ||
50 | return `${this.getTokenType()} ${this.getToken()}`; | ||
47 | } | 51 | } |
48 | 52 | ||
49 | getToken() { | 53 | getToken() { |
diff --git a/client/src/app/videos/video-add/video-add.component.html b/client/src/app/videos/video-add/video-add.component.html index cbe274e8a..6b2eb9377 100644 --- a/client/src/app/videos/video-add/video-add.component.html +++ b/client/src/app/videos/video-add/video-add.component.html | |||
@@ -2,42 +2,74 @@ | |||
2 | 2 | ||
3 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | 3 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> |
4 | 4 | ||
5 | <form (ngSubmit)="uploadFile()" #videoForm="ngForm"> | 5 | <form novalidate (ngSubmit)="upload()" [ngFormModel]="videoForm"> |
6 | <div class="form-group"> | 6 | <div class="form-group"> |
7 | <label for="name">Video name</label> | 7 | <label for="name">Name</label> |
8 | <input | 8 | <input |
9 | type="text" class="form-control" name="name" id="name" required | 9 | type="text" class="form-control" name="name" id="name" |
10 | ngControl="name" #name="ngForm" | 10 | ngControl="name" #name="ngForm" [(ngModel)]="video.name" |
11 | > | 11 | > |
12 | <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> | 12 | <div [hidden]="name.valid || name.pristine" class="alert alert-warning"> |
13 | Name is required | 13 | A name is required and should be between 3 and 50 characters long |
14 | </div> | 14 | </div> |
15 | </div> | 15 | </div> |
16 | 16 | ||
17 | <div class="form-group"> | 17 | <div class="form-group"> |
18 | <div class="btn btn-default btn-file"> | 18 | <label for="tags">Tags</label> |
19 | <input | ||
20 | type="text" class="form-control" name="tags" id="tags" | ||
21 | ngControl="tags" #tags="ngForm" [disabled]="isTagsInputDisabled" (keyup)="onTagKeyPress($event)" [(ngModel)]="currentTag" | ||
22 | > | ||
23 | <div [hidden]="tags.valid || tags.pristine" class="alert alert-warning"> | ||
24 | A tag should be between 2 and 10 characters long | ||
25 | </div> | ||
26 | </div> | ||
27 | |||
28 | <div class="tags"> | ||
29 | <div class="label label-info tag" *ngFor="let tag of video.tags"> | ||
30 | {{ tag }} | ||
31 | <span class="remove" (click)="removeTag(tag)">x</span> | ||
32 | </div> | ||
33 | </div> | ||
34 | |||
35 | <div class="form-group"> | ||
36 | <label for="videofile">File</label> | ||
37 | <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" > | ||
19 | <span>Select the video...</span> | 38 | <span>Select the video...</span> |
20 | <input type="file" name="videofile" id="videofile"> | 39 | <input |
40 | type="file" name="videofile" id="videofile" | ||
41 | ng2FileSelect [uploader]="uploader" [disabled]="filename !== null" | ||
42 | > | ||
21 | </div> | 43 | </div> |
44 | </div> | ||
22 | 45 | ||
23 | <span *ngIf="fileToUpload">{{ fileToUpload.name }}</span> | 46 | <div class="file-to-upload"> |
47 | <div class="file" *ngIf="uploader.queue.length > 0"> | ||
48 | <span class="filename">{{ filename }}</span> | ||
49 | <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span> | ||
50 | </div> | ||
24 | </div> | 51 | </div> |
25 | 52 | ||
26 | <div class="form-group"> | 53 | <div class="form-group"> |
27 | <label for="description">Description</label> | 54 | <label for="description">Description</label> |
28 | <textarea | 55 | <textarea |
29 | name="description" id="description" class="form-control" placeholder="Description..." required | 56 | name="description" id="description" class="form-control" placeholder="Description..." |
30 | ngControl="description" #description="ngForm" | 57 | ngControl="description" #description="ngForm" [(ngModel)]="video.description" |
31 | > | 58 | > |
32 | </textarea> | 59 | </textarea> |
33 | <div [hidden]="description.valid || description.pristine" class="alert alert-danger"> | 60 | <div [hidden]="description.valid || description.pristine" class="alert alert-warning"> |
34 | A description is required | 61 | A description is required and should be between 3 and 250 characters long |
35 | </div> | 62 | </div> |
36 | </div> | 63 | </div> |
37 | 64 | ||
38 | <div id="progress" *ngIf="progressBar.max !== 0"> | 65 | <div class="progress"> |
39 | <progressbar [value]="progressBar.value" [max]="progressBar.max">{{ progressBar.value | bytes }} / {{ progressBar.max | bytes }}</progressbar> | 66 | <progressbar [value]="uploader.progress" max="100"></progressbar> |
40 | </div> | 67 | </div> |
41 | 68 | ||
42 | <input type="submit" value="Upload" class="btn btn-default" [disabled]="!videoForm.form.valid || !fileToUpload"> | 69 | <div class="form-group"> |
70 | <input | ||
71 | type="submit" value="Upload" class="btn btn-default form-control" [title]="getInvalidFieldsTitle()" | ||
72 | [disabled]="!videoForm.valid || video.tags.length === 0 || filename === null" | ||
73 | > | ||
74 | </div> | ||
43 | </form> | 75 | </form> |
diff --git a/client/src/app/videos/video-add/video-add.component.scss b/client/src/app/videos/video-add/video-add.component.scss index 01195f017..d66df2fd4 100644 --- a/client/src/app/videos/video-add/video-add.component.scss +++ b/client/src/app/videos/video-add/video-add.component.scss | |||
@@ -1,6 +1,7 @@ | |||
1 | .btn-file { | 1 | .btn-file { |
2 | position: relative; | 2 | position: relative; |
3 | overflow: hidden; | 3 | overflow: hidden; |
4 | display: block; | ||
4 | } | 5 | } |
5 | 6 | ||
6 | .btn-file input[type=file] { | 7 | .btn-file input[type=file] { |
@@ -28,6 +29,28 @@ | |||
28 | margin-bottom: 10px; | 29 | margin-bottom: 10px; |
29 | } | 30 | } |
30 | 31 | ||
31 | #progress { | 32 | div.tags { |
32 | margin-bottom: 10px; | 33 | height: 40px; |
34 | font-size: 20px; | ||
35 | margin-top: 20px; | ||
36 | |||
37 | .tag { | ||
38 | margin-right: 10px; | ||
39 | |||
40 | .remove { | ||
41 | cursor: pointer; | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | div.file-to-upload { | ||
47 | height: 40px; | ||
48 | |||
49 | .glyphicon-remove { | ||
50 | cursor: pointer; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | div.progress { | ||
55 | // height: 40px; | ||
33 | } | 56 | } |
diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-add/video-add.component.ts index 144879a54..2b45ea125 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-add/video-add.component.ts | |||
@@ -1,29 +1,31 @@ | |||
1 | /// <reference path="../../../../typings/globals/jquery/index.d.ts" /> | 1 | import { Control, ControlGroup, Validators } from '@angular/common'; |
2 | /// <reference path="../../../../typings/globals/jquery.fileupload/index.d.ts" /> | ||
3 | |||
4 | import { Component, ElementRef, OnInit } from '@angular/core'; | 2 | import { Component, ElementRef, OnInit } from '@angular/core'; |
5 | import { Router } from '@angular/router-deprecated'; | 3 | import { Router } from '@angular/router-deprecated'; |
6 | 4 | ||
7 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; | 5 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; |
8 | import { PROGRESSBAR_DIRECTIVES } from 'ng2-bootstrap/components/progressbar'; | 6 | import { PROGRESSBAR_DIRECTIVES } from 'ng2-bootstrap/components/progressbar'; |
7 | import { FileSelectDirective, FileUploader } from 'ng2-file-upload/ng2-file-upload'; | ||
9 | 8 | ||
10 | import { AuthService, User } from '../../shared'; | 9 | import { AuthService } from '../../shared'; |
11 | 10 | ||
12 | @Component({ | 11 | @Component({ |
13 | selector: 'my-videos-add', | 12 | selector: 'my-videos-add', |
14 | styles: [ require('./video-add.component.scss') ], | 13 | styles: [ require('./video-add.component.scss') ], |
15 | template: require('./video-add.component.html'), | 14 | template: require('./video-add.component.html'), |
16 | directives: [ PROGRESSBAR_DIRECTIVES ], | 15 | directives: [ FileSelectDirective, PROGRESSBAR_DIRECTIVES ], |
17 | pipes: [ BytesPipe ] | 16 | pipes: [ BytesPipe ] |
18 | }) | 17 | }) |
19 | 18 | ||
20 | export class VideoAddComponent implements OnInit { | 19 | export class VideoAddComponent implements OnInit { |
20 | currentTag: string; // Tag the user is writing in the input | ||
21 | error: string = null; | 21 | error: string = null; |
22 | fileToUpload: any; | 22 | videoForm: ControlGroup; |
23 | progressBar: { value: number; max: number; } = { value: 0, max: 0 }; | 23 | uploader: FileUploader; |
24 | user: User; | 24 | video = { |
25 | 25 | name: '', | |
26 | private form: any; | 26 | tags: [], |
27 | description: '' | ||
28 | }; | ||
27 | 29 | ||
28 | constructor( | 30 | constructor( |
29 | private authService: AuthService, | 31 | private authService: AuthService, |
@@ -31,52 +33,108 @@ export class VideoAddComponent implements OnInit { | |||
31 | private router: Router | 33 | private router: Router |
32 | ) {} | 34 | ) {} |
33 | 35 | ||
36 | get filename() { | ||
37 | if (this.uploader.queue.length === 0) { | ||
38 | return null; | ||
39 | } | ||
40 | |||
41 | return this.uploader.queue[0].file.name; | ||
42 | } | ||
43 | |||
44 | get isTagsInputDisabled () { | ||
45 | return this.video.tags.length >= 3; | ||
46 | } | ||
47 | |||
48 | getInvalidFieldsTitle() { | ||
49 | let title = ''; | ||
50 | const nameControl = this.videoForm.controls['name']; | ||
51 | const descriptionControl = this.videoForm.controls['description']; | ||
52 | |||
53 | if (!nameControl.valid) { | ||
54 | title += 'A name is required\n'; | ||
55 | } | ||
56 | |||
57 | if (this.video.tags.length === 0) { | ||
58 | title += 'At least one tag is required\n'; | ||
59 | } | ||
60 | |||
61 | if (this.filename === null) { | ||
62 | title += 'A file is required\n'; | ||
63 | } | ||
64 | |||
65 | if (!descriptionControl.valid) { | ||
66 | title += 'A description is required\n'; | ||
67 | } | ||
68 | |||
69 | return title; | ||
70 | } | ||
71 | |||
34 | ngOnInit() { | 72 | ngOnInit() { |
35 | this.user = User.load(); | 73 | this.videoForm = new ControlGroup({ |
36 | jQuery(this.elementRef.nativeElement).find('#videofile').fileupload({ | 74 | name: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(50) ])), |
75 | description: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(250) ])), | ||
76 | tags: new Control('', Validators.pattern('^[a-zA-Z0-9]{2,10}$')) | ||
77 | }); | ||
78 | |||
79 | |||
80 | this.uploader = new FileUploader({ | ||
81 | authToken: this.authService.getRequestHeaderValue(), | ||
82 | queueLimit: 1, | ||
37 | url: '/api/v1/videos', | 83 | url: '/api/v1/videos', |
38 | dataType: 'json', | 84 | removeAfterUpload: true |
39 | singleFileUploads: true, | ||
40 | multipart: true, | ||
41 | autoUpload: false, | ||
42 | |||
43 | add: (e, data) => { | ||
44 | this.form = data; | ||
45 | this.fileToUpload = data['files'][0]; | ||
46 | }, | ||
47 | |||
48 | progressall: (e, data) => { | ||
49 | this.progressBar.value = data.loaded; | ||
50 | // The server is a little bit slow to answer (has to seed the video) | ||
51 | // So we add more time to the progress bar (+10%) | ||
52 | this.progressBar.max = data.total + (0.1 * data.total); | ||
53 | }, | ||
54 | |||
55 | done: (e, data) => { | ||
56 | this.progressBar.value = this.progressBar.max; | ||
57 | console.log('Video uploaded.'); | ||
58 | |||
59 | // Print all the videos once it's finished | ||
60 | this.router.navigate(['VideosList']); | ||
61 | }, | ||
62 | |||
63 | fail: (e, data) => { | ||
64 | const xhr = data.jqXHR; | ||
65 | if (xhr.status === 400) { | ||
66 | this.error = xhr.responseText; | ||
67 | } else { | ||
68 | this.error = 'Unknow error'; | ||
69 | } | ||
70 | |||
71 | console.error(data); | ||
72 | } | ||
73 | }); | 85 | }); |
86 | |||
87 | this.uploader.onBuildItemForm = (item, form) => { | ||
88 | form.append('name', this.video.name); | ||
89 | form.append('description', this.video.description); | ||
90 | |||
91 | for (let i = 0; i < this.video.tags.length; i++) { | ||
92 | form.append(`tags[${i}]`, this.video.tags[i]); | ||
93 | } | ||
94 | }; | ||
95 | } | ||
96 | |||
97 | onTagKeyPress(event: KeyboardEvent) { | ||
98 | // Enter press | ||
99 | if (event.keyCode === 13) { | ||
100 | // Check if the tag is valid and does not already exist | ||
101 | if ( | ||
102 | this.currentTag !== '' && | ||
103 | this.videoForm.controls['tags'].valid && | ||
104 | this.video.tags.indexOf(this.currentTag) === -1 | ||
105 | ) { | ||
106 | this.video.tags.push(this.currentTag); | ||
107 | this.currentTag = ''; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | removeFile() { | ||
113 | this.uploader.clearQueue(); | ||
114 | } | ||
115 | |||
116 | removeTag(tag: string) { | ||
117 | this.video.tags.splice(this.video.tags.indexOf(tag), 1); | ||
74 | } | 118 | } |
75 | 119 | ||
76 | uploadFile() { | 120 | upload() { |
77 | this.error = null; | 121 | const item = this.uploader.queue[0]; |
78 | this.form.formData = jQuery(this.elementRef.nativeElement).find('form').serializeArray(); | 122 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 |
79 | this.form.headers = this.authService.getRequestHeader().toJSON(); | 123 | item.alias = 'videofile'; |
80 | this.form.submit(); | 124 | |
125 | item.onSuccess = () => { | ||
126 | console.log('Video uploaded.'); | ||
127 | |||
128 | // Print all the videos once it's finished | ||
129 | this.router.navigate(['VideosList']); | ||
130 | }; | ||
131 | |||
132 | item.onError = (response: string, status: number) => { | ||
133 | this.error = (status === 400) ? response : 'Unknow error'; | ||
134 | console.error(this.error); | ||
135 | }; | ||
136 | |||
137 | |||
138 | this.uploader.uploadAll(); | ||
81 | } | 139 | } |
82 | } | 140 | } |
diff --git a/client/src/vendor.ts b/client/src/vendor.ts index 496f44cf6..437d05822 100644 --- a/client/src/vendor.ts +++ b/client/src/vendor.ts | |||
@@ -18,7 +18,5 @@ import 'rxjs/add/operator/catch'; | |||
18 | import 'rxjs/add/operator/map'; | 18 | import 'rxjs/add/operator/map'; |
19 | import 'rxjs/add/operator/mergeMap'; | 19 | import 'rxjs/add/operator/mergeMap'; |
20 | 20 | ||
21 | import 'jquery'; | ||
22 | import 'bootstrap-loader'; | 21 | import 'bootstrap-loader'; |
23 | import 'jquery.ui.widget/jquery.ui.widget'; | 22 | import 'ng2-file-upload'; |
24 | import 'blueimp-file-upload'; | ||
diff --git a/client/tsconfig.json b/client/tsconfig.json index 3b903f8c8..fdcf742ea 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json | |||
@@ -65,8 +65,6 @@ | |||
65 | "src/vendor.ts", | 65 | "src/vendor.ts", |
66 | "typings/globals/es6-shim/index.d.ts", | 66 | "typings/globals/es6-shim/index.d.ts", |
67 | "typings/globals/jasmine/index.d.ts", | 67 | "typings/globals/jasmine/index.d.ts", |
68 | "typings/globals/jquery.fileupload/index.d.ts", | ||
69 | "typings/globals/jquery/index.d.ts", | ||
70 | "typings/globals/node/index.d.ts", | 68 | "typings/globals/node/index.d.ts", |
71 | "typings/index.d.ts" | 69 | "typings/index.d.ts" |
72 | ] | 70 | ] |
diff --git a/client/typings.json b/client/typings.json index ff8b56a48..9a8891f25 100644 --- a/client/typings.json +++ b/client/typings.json | |||
@@ -2,8 +2,6 @@ | |||
2 | "globalDependencies": { | 2 | "globalDependencies": { |
3 | "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654", | 3 | "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654", |
4 | "jasmine": "registry:dt/jasmine#2.2.0+20160412134438", | 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160412134438", |
5 | "jquery": "registry:dt/jquery#1.10.0+20160417213236", | ||
6 | "jquery.fileupload": "registry:dt/jquery.fileupload#5.40.1+20160316155526", | ||
7 | "node": "registry:dt/node#4.0.0+20160509154515" | 5 | "node": "registry:dt/node#4.0.0+20160509154515" |
8 | } | 6 | } |
9 | } | 7 | } |
diff --git a/server/initializers/constants.js b/server/initializers/constants.js index 6fa322010..22cbb1361 100644 --- a/server/initializers/constants.js +++ b/server/initializers/constants.js | |||
@@ -41,8 +41,8 @@ const THUMBNAILS_SIZE = '200x110' | |||
41 | const THUMBNAILS_STATIC_PATH = '/static/thumbnails' | 41 | const THUMBNAILS_STATIC_PATH = '/static/thumbnails' |
42 | 42 | ||
43 | const VIDEOS_CONSTRAINTS_FIELDS = { | 43 | const VIDEOS_CONSTRAINTS_FIELDS = { |
44 | NAME: { min: 1, max: 50 }, // Length | 44 | NAME: { min: 3, max: 50 }, // Length |
45 | DESCRIPTION: { min: 1, max: 250 }, // Length | 45 | DESCRIPTION: { min: 3, max: 250 }, // Length |
46 | MAGNET_URI: { min: 10 }, // Length | 46 | MAGNET_URI: { min: 10 }, // Length |
47 | DURATION: { min: 1, max: 7200 }, // Number | 47 | DURATION: { min: 1, max: 7200 }, // Number |
48 | AUTHOR: { min: 3, max: 20 }, // Length | 48 | AUTHOR: { min: 3, max: 20 }, // Length |
diff --git a/server/middlewares/reqValidators/videos.js b/server/middlewares/reqValidators/videos.js index 3618e4716..f31fd93a2 100644 --- a/server/middlewares/reqValidators/videos.js +++ b/server/middlewares/reqValidators/videos.js | |||
@@ -32,7 +32,7 @@ function videosAdd (req, res, next) { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | if (!customValidators.isVideoDurationValid(duration)) { | 34 | if (!customValidators.isVideoDurationValid(duration)) { |
35 | return res.status(400).send('Duration of the video file is too big (max: ' + constants.MAXIMUM_VIDEO_DURATION + 's).') | 35 | return res.status(400).send('Duration of the video file is too big (max: ' + constants.VIDEOS_CONSTRAINTS_FIELDS.DURATION.max + 's).') |
36 | } | 36 | } |
37 | 37 | ||
38 | videoFile.duration = duration | 38 | videoFile.duration = duration |
diff --git a/server/models/videos.js b/server/models/videos.js index d6b743c7c..c177b414c 100644 --- a/server/models/videos.js +++ b/server/models/videos.js | |||
@@ -12,6 +12,7 @@ const port = config.get('webserver.port') | |||
12 | 12 | ||
13 | // --------------------------------------------------------------------------- | 13 | // --------------------------------------------------------------------------- |
14 | 14 | ||
15 | // TODO: add indexes on searchable columns | ||
15 | const videosSchema = mongoose.Schema({ | 16 | const videosSchema = mongoose.Schema({ |
16 | name: String, | 17 | name: String, |
17 | namePath: String, | 18 | namePath: String, |