diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-12-07 17:03:56 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-12-07 17:05:23 +0100 |
commit | 8e7f08b5a5e65195ad6dd3d7850fda57021421f3 (patch) | |
tree | 1ee2bff1a5a51643e6b86c6f21e4766013a9213d | |
parent | 27e1a06c331278e5d37bc5172ee7e4fc968e4b5e (diff) | |
download | PeerTube-8e7f08b5a5e65195ad6dd3d7850fda57021421f3.tar.gz PeerTube-8e7f08b5a5e65195ad6dd3d7850fda57021421f3.tar.zst PeerTube-8e7f08b5a5e65195ad6dd3d7850fda57021421f3.zip |
Make some fields optional when uploading a video
-rw-r--r-- | server/initializers/migrations/0120-video-null.ts | 46 | ||||
-rw-r--r-- | server/middlewares/validators/videos.ts | 6 | ||||
-rw-r--r-- | server/models/video/video.ts | 16 | ||||
-rw-r--r-- | server/tests/api/check-params/videos.ts | 24 | ||||
-rw-r--r-- | server/tests/api/single-server.ts | 82 |
5 files changed, 117 insertions, 57 deletions
diff --git a/server/initializers/migrations/0120-video-null.ts b/server/initializers/migrations/0120-video-null.ts new file mode 100644 index 000000000..3506a5046 --- /dev/null +++ b/server/initializers/migrations/0120-video-null.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import { PeerTubeDatabase } from '../database' | ||
3 | |||
4 | async function up (utils: { | ||
5 | transaction: Sequelize.Transaction, | ||
6 | queryInterface: Sequelize.QueryInterface, | ||
7 | sequelize: Sequelize.Sequelize, | ||
8 | db: PeerTubeDatabase | ||
9 | }): Promise<void> { | ||
10 | |||
11 | { | ||
12 | const data = { | ||
13 | type: Sequelize.INTEGER, | ||
14 | allowNull: true, | ||
15 | defaultValue: null | ||
16 | } | ||
17 | await utils.queryInterface.changeColumn('Videos', 'licence', data) | ||
18 | } | ||
19 | |||
20 | { | ||
21 | const data = { | ||
22 | type: Sequelize.INTEGER, | ||
23 | allowNull: true, | ||
24 | defaultValue: null | ||
25 | } | ||
26 | await utils.queryInterface.changeColumn('Videos', 'category', data) | ||
27 | } | ||
28 | |||
29 | { | ||
30 | const data = { | ||
31 | type: Sequelize.INTEGER, | ||
32 | allowNull: true, | ||
33 | defaultValue: null | ||
34 | } | ||
35 | await utils.queryInterface.changeColumn('Videos', 'description', data) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | function down (options) { | ||
40 | throw new Error('Not implemented.') | ||
41 | } | ||
42 | |||
43 | export { | ||
44 | up, | ||
45 | down | ||
46 | } | ||
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index ee2ac50c8..10625e41d 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts | |||
@@ -31,11 +31,11 @@ const videosAddValidator = [ | |||
31 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') | 31 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') |
32 | ), | 32 | ), |
33 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), | 33 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), |
34 | body('category').custom(isVideoCategoryValid).withMessage('Should have a valid category'), | 34 | body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'), |
35 | body('licence').custom(isVideoLicenceValid).withMessage('Should have a valid licence'), | 35 | body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'), |
36 | body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'), | 36 | body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'), |
37 | body('nsfw').custom(isVideoNSFWValid).withMessage('Should have a valid NSFW attribute'), | 37 | body('nsfw').custom(isVideoNSFWValid).withMessage('Should have a valid NSFW attribute'), |
38 | body('description').custom(isVideoDescriptionValid).withMessage('Should have a valid description'), | 38 | body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'), |
39 | body('channelId').custom(isIdValid).withMessage('Should have correct video channel id'), | 39 | body('channelId').custom(isIdValid).withMessage('Should have correct video channel id'), |
40 | body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'), | 40 | body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'), |
41 | body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), | 41 | body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 60023bc8c..8b1eb1f96 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -104,7 +104,8 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
104 | }, | 104 | }, |
105 | category: { | 105 | category: { |
106 | type: DataTypes.INTEGER, | 106 | type: DataTypes.INTEGER, |
107 | allowNull: false, | 107 | allowNull: true, |
108 | defaultValue: null, | ||
108 | validate: { | 109 | validate: { |
109 | categoryValid: value => { | 110 | categoryValid: value => { |
110 | const res = isVideoCategoryValid(value) | 111 | const res = isVideoCategoryValid(value) |
@@ -114,7 +115,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
114 | }, | 115 | }, |
115 | licence: { | 116 | licence: { |
116 | type: DataTypes.INTEGER, | 117 | type: DataTypes.INTEGER, |
117 | allowNull: false, | 118 | allowNull: true, |
118 | defaultValue: null, | 119 | defaultValue: null, |
119 | validate: { | 120 | validate: { |
120 | licenceValid: value => { | 121 | licenceValid: value => { |
@@ -126,6 +127,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
126 | language: { | 127 | language: { |
127 | type: DataTypes.INTEGER, | 128 | type: DataTypes.INTEGER, |
128 | allowNull: true, | 129 | allowNull: true, |
130 | defaultValue: null, | ||
129 | validate: { | 131 | validate: { |
130 | languageValid: value => { | 132 | languageValid: value => { |
131 | const res = isVideoLanguageValid(value) | 133 | const res = isVideoLanguageValid(value) |
@@ -155,7 +157,8 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
155 | }, | 157 | }, |
156 | description: { | 158 | description: { |
157 | type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max), | 159 | type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max), |
158 | allowNull: false, | 160 | allowNull: true, |
161 | defaultValue: null, | ||
159 | validate: { | 162 | validate: { |
160 | descriptionValid: value => { | 163 | descriptionValid: value => { |
161 | const res = isVideoDescriptionValid(value) | 164 | const res = isVideoDescriptionValid(value) |
@@ -664,6 +667,8 @@ toActivityPubObject = function (this: VideoInstance) { | |||
664 | } | 667 | } |
665 | 668 | ||
666 | getTruncatedDescription = function (this: VideoInstance) { | 669 | getTruncatedDescription = function (this: VideoInstance) { |
670 | if (!this.description) return null | ||
671 | |||
667 | const options = { | 672 | const options = { |
668 | length: CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max | 673 | length: CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max |
669 | } | 674 | } |
@@ -754,8 +759,6 @@ getDescriptionPath = function (this: VideoInstance) { | |||
754 | 759 | ||
755 | getCategoryLabel = function (this: VideoInstance) { | 760 | getCategoryLabel = function (this: VideoInstance) { |
756 | let categoryLabel = VIDEO_CATEGORIES[this.category] | 761 | let categoryLabel = VIDEO_CATEGORIES[this.category] |
757 | |||
758 | // Maybe our server is not up to date and there are new categories since our version | ||
759 | if (!categoryLabel) categoryLabel = 'Misc' | 762 | if (!categoryLabel) categoryLabel = 'Misc' |
760 | 763 | ||
761 | return categoryLabel | 764 | return categoryLabel |
@@ -763,15 +766,12 @@ getCategoryLabel = function (this: VideoInstance) { | |||
763 | 766 | ||
764 | getLicenceLabel = function (this: VideoInstance) { | 767 | getLicenceLabel = function (this: VideoInstance) { |
765 | let licenceLabel = VIDEO_LICENCES[this.licence] | 768 | let licenceLabel = VIDEO_LICENCES[this.licence] |
766 | |||
767 | // Maybe our server is not up to date and there are new licences since our version | ||
768 | if (!licenceLabel) licenceLabel = 'Unknown' | 769 | if (!licenceLabel) licenceLabel = 'Unknown' |
769 | 770 | ||
770 | return licenceLabel | 771 | return licenceLabel |
771 | } | 772 | } |
772 | 773 | ||
773 | getLanguageLabel = function (this: VideoInstance) { | 774 | getLanguageLabel = function (this: VideoInstance) { |
774 | // Language is an optional attribute | ||
775 | let languageLabel = VIDEO_LANGUAGES[this.language] | 775 | let languageLabel = VIDEO_LANGUAGES[this.language] |
776 | if (!languageLabel) languageLabel = 'Unknown' | 776 | if (!languageLabel) languageLabel = 'Unknown' |
777 | 777 | ||
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 2962f5640..00a209665 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -189,14 +189,6 @@ describe('Test videos API validator', function () { | |||
189 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 189 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
190 | }) | 190 | }) |
191 | 191 | ||
192 | it('Should fail without a category', async function () { | ||
193 | const fields = getCompleteVideoUploadAttributes() | ||
194 | delete fields.category | ||
195 | |||
196 | const attaches = getVideoUploadAttaches | ||
197 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | ||
198 | }) | ||
199 | |||
200 | it('Should fail with a bad category', async function () { | 192 | it('Should fail with a bad category', async function () { |
201 | const fields = getCompleteVideoUploadAttributes() | 193 | const fields = getCompleteVideoUploadAttributes() |
202 | fields.category = 125 | 194 | fields.category = 125 |
@@ -205,14 +197,6 @@ describe('Test videos API validator', function () { | |||
205 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 197 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
206 | }) | 198 | }) |
207 | 199 | ||
208 | it('Should fail without a licence', async function () { | ||
209 | const fields = getCompleteVideoUploadAttributes() | ||
210 | delete fields.licence | ||
211 | |||
212 | const attaches = getVideoUploadAttaches() | ||
213 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | ||
214 | }) | ||
215 | |||
216 | it('Should fail with a bad licence', async function () { | 200 | it('Should fail with a bad licence', async function () { |
217 | const fields = getCompleteVideoUploadAttributes() | 201 | const fields = getCompleteVideoUploadAttributes() |
218 | fields.licence = 125 | 202 | fields.licence = 125 |
@@ -245,14 +229,6 @@ describe('Test videos API validator', function () { | |||
245 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 229 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
246 | }) | 230 | }) |
247 | 231 | ||
248 | it('Should fail without description', async function () { | ||
249 | const fields = getCompleteVideoUploadAttributes() | ||
250 | delete fields.description | ||
251 | |||
252 | const attaches = getVideoUploadAttaches() | ||
253 | await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | ||
254 | }) | ||
255 | |||
256 | it('Should fail with a long description', async function () { | 232 | it('Should fail with a long description', async function () { |
257 | const fields = getCompleteVideoUploadAttributes() | 233 | const fields = getCompleteVideoUploadAttributes() |
258 | fields.description = 'my super description which is very very very very very very very very very very very very long'.repeat(35) | 234 | fields.description = 'my super description which is very very very very very very very very very very very very long'.repeat(35) |
diff --git a/server/tests/api/single-server.ts b/server/tests/api/single-server.ts index d7e9ad41f..fbb2dd1fb 100644 --- a/server/tests/api/single-server.ts +++ b/server/tests/api/single-server.ts | |||
@@ -1,40 +1,41 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* tslint:disable:no-unused-expression */ |
2 | 2 | ||
3 | import * as chai from 'chai' | ||
3 | import { keyBy } from 'lodash' | 4 | import { keyBy } from 'lodash' |
4 | import { join } from 'path' | ||
5 | import 'mocha' | 5 | import 'mocha' |
6 | import * as chai from 'chai' | 6 | import { join } from 'path' |
7 | const expect = chai.expect | 7 | import * as request from 'supertest' |
8 | |||
9 | import { | 8 | import { |
10 | ServerInfo, | ||
11 | flushTests, | ||
12 | runServer, | ||
13 | uploadVideo, | ||
14 | getVideosList, | ||
15 | rateVideo, | ||
16 | removeVideo, | ||
17 | wait, | ||
18 | setAccessTokensToServers, | ||
19 | searchVideo, | ||
20 | killallServers, | ||
21 | dateIsValid, | 9 | dateIsValid, |
10 | flushTests, | ||
11 | getVideo, | ||
22 | getVideoCategories, | 12 | getVideoCategories, |
23 | getVideoLicences, | ||
24 | getVideoLanguages, | 13 | getVideoLanguages, |
14 | getVideoLicences, | ||
25 | getVideoPrivacies, | 15 | getVideoPrivacies, |
26 | testVideoImage, | 16 | getVideosList, |
27 | webtorrentAdd, | ||
28 | getVideo, | ||
29 | readdirPromise, | ||
30 | getVideosListPagination, | 17 | getVideosListPagination, |
31 | searchVideoWithPagination, | ||
32 | getVideosListSort, | 18 | getVideosListSort, |
19 | killallServers, | ||
20 | rateVideo, | ||
21 | readdirPromise, | ||
22 | removeVideo, | ||
23 | runServer, | ||
24 | searchVideo, | ||
25 | searchVideoWithPagination, | ||
33 | searchVideoWithSort, | 26 | searchVideoWithSort, |
34 | updateVideo | 27 | ServerInfo, |
28 | setAccessTokensToServers, | ||
29 | testVideoImage, | ||
30 | updateVideo, | ||
31 | uploadVideo, | ||
32 | wait, | ||
33 | webtorrentAdd | ||
35 | } from '../utils' | 34 | } from '../utils' |
36 | import { viewVideo } from '../utils/videos' | 35 | import { viewVideo } from '../utils/videos' |
37 | 36 | ||
37 | const expect = chai.expect | ||
38 | |||
38 | describe('Test a single server', function () { | 39 | describe('Test a single server', function () { |
39 | let server: ServerInfo = null | 40 | let server: ServerInfo = null |
40 | let videoId = -1 | 41 | let videoId = -1 |
@@ -693,6 +694,43 @@ describe('Test a single server', function () { | |||
693 | expect(video.dislikes).to.equal(1) | 694 | expect(video.dislikes).to.equal(1) |
694 | }) | 695 | }) |
695 | 696 | ||
697 | it('Should upload a video with minimum parameters', async function () { | ||
698 | const path = '/api/v1/videos/upload' | ||
699 | |||
700 | const req = request(server.url) | ||
701 | .post(path) | ||
702 | .set('Accept', 'application/json') | ||
703 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
704 | .field('name', 'minimum parameters') | ||
705 | .field('privacy', '1') | ||
706 | .field('nsfw', 'false') | ||
707 | .field('channelId', '1') | ||
708 | |||
709 | const filePath = join(__dirname, '..', 'api', 'fixtures', 'video_short.webm') | ||
710 | |||
711 | await req.attach('videofile', filePath) | ||
712 | .expect(204) | ||
713 | |||
714 | const res = await getVideosList(server.url) | ||
715 | const video = res.body.data.find(v => v.name === 'minimum parameters') | ||
716 | |||
717 | expect(video.name).to.equal('minimum parameters') | ||
718 | expect(video.category).to.equal(null) | ||
719 | expect(video.categoryLabel).to.equal('Misc') | ||
720 | expect(video.licence).to.equal(null) | ||
721 | expect(video.licenceLabel).to.equal('Unknown') | ||
722 | expect(video.language).to.equal(null) | ||
723 | expect(video.languageLabel).to.equal('Unknown') | ||
724 | expect(video.nsfw).to.not.be.ok | ||
725 | expect(video.description).to.equal(null) | ||
726 | expect(video.serverHost).to.equal('localhost:9001') | ||
727 | expect(video.accountName).to.equal('root') | ||
728 | expect(video.isLocal).to.be.true | ||
729 | expect(video.tags).to.deep.equal([ ]) | ||
730 | expect(dateIsValid(video.createdAt)).to.be.true | ||
731 | expect(dateIsValid(video.updatedAt)).to.be.true | ||
732 | }) | ||
733 | |||
696 | after(async function () { | 734 | after(async function () { |
697 | killallServers([ server ]) | 735 | killallServers([ server ]) |
698 | 736 | ||