Add tests and fix bugs for video privacy
[oweals/peertube.git] / server / tests / utils / videos.ts
1 import { readFile } from 'fs'
2 import * as request from 'supertest'
3 import { join, isAbsolute } from 'path'
4 import * as parseTorrent from 'parse-torrent'
5
6 import { makeGetRequest } from './requests'
7 import { readFilePromise } from './miscs'
8 import { ServerInfo } from './servers'
9 import { getMyUserInformation } from './users'
10 import { VideoPrivacy } from '../../../shared'
11
12 type VideoAttributes = {
13   name?: string
14   category?: number
15   licence?: number
16   language?: number
17   nsfw?: boolean
18   description?: string
19   tags?: string[]
20   channelId?: number
21   privacy?: VideoPrivacy
22   fixture?: string
23 }
24
25 function getVideoCategories (url: string) {
26   const path = '/api/v1/videos/categories'
27
28   return makeGetRequest(url, path)
29 }
30
31 function getVideoLicences (url: string) {
32   const path = '/api/v1/videos/licences'
33
34   return makeGetRequest(url, path)
35 }
36
37 function getVideoLanguages (url: string) {
38   const path = '/api/v1/videos/languages'
39
40   return makeGetRequest(url, path)
41 }
42
43 function getVideoPrivacies (url: string) {
44   const path = '/api/v1/videos/privacies'
45
46   return makeGetRequest(url, path)
47 }
48
49 function getAllVideosListBy (url: string) {
50   const path = '/api/v1/videos'
51
52   return request(url)
53           .get(path)
54           .query({ sort: 'createdAt' })
55           .query({ start: 0 })
56           .query({ count: 10000 })
57           .set('Accept', 'application/json')
58           .expect(200)
59           .expect('Content-Type', /json/)
60 }
61
62 function getVideo (url: string, id: number | string, expectedStatus = 200) {
63   const path = '/api/v1/videos/' + id
64
65   return request(url)
66           .get(path)
67           .set('Accept', 'application/json')
68           .expect(expectedStatus)
69 }
70
71 function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
72   const path = '/api/v1/videos/' + id
73
74   return request(url)
75     .get(path)
76     .set('Authorization', 'Bearer ' + token)
77     .set('Accept', 'application/json')
78     .expect(expectedStatus)
79 }
80
81 function getVideoDescription (url: string, descriptionPath: string) {
82   return request(url)
83     .get(descriptionPath)
84     .set('Accept', 'application/json')
85     .expect(200)
86     .expect('Content-Type', /json/)
87 }
88
89 function getVideosList (url: string) {
90   const path = '/api/v1/videos'
91
92   return request(url)
93           .get(path)
94           .query({ sort: 'name' })
95           .set('Accept', 'application/json')
96           .expect(200)
97           .expect('Content-Type', /json/)
98 }
99
100 function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
101   const path = '/api/v1/users/me/videos'
102
103   const req = request(url)
104     .get(path)
105     .query({ start: start })
106     .query({ count: count })
107
108   if (sort) req.query({ sort })
109
110   return req.set('Accept', 'application/json')
111     .set('Authorization', 'Bearer ' + accessToken)
112     .expect(200)
113     .expect('Content-Type', /json/)
114 }
115
116 function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
117   const path = '/api/v1/videos'
118
119   const req = request(url)
120               .get(path)
121               .query({ start: start })
122               .query({ count: count })
123
124   if (sort) req.query({ sort })
125
126   return req.set('Accept', 'application/json')
127            .expect(200)
128            .expect('Content-Type', /json/)
129 }
130
131 function getVideosListSort (url: string, sort: string) {
132   const path = '/api/v1/videos'
133
134   return request(url)
135           .get(path)
136           .query({ sort: sort })
137           .set('Accept', 'application/json')
138           .expect(200)
139           .expect('Content-Type', /json/)
140 }
141
142 function removeVideo (url: string, token: string, id: number, expectedStatus = 204) {
143   const path = '/api/v1/videos'
144
145   return request(url)
146           .delete(path + '/' + id)
147           .set('Accept', 'application/json')
148           .set('Authorization', 'Bearer ' + token)
149           .expect(expectedStatus)
150 }
151
152 function searchVideo (url: string, search: string, field?: string) {
153   const path = '/api/v1/videos'
154   const req = request(url)
155                 .get(path + '/search/' + search)
156                 .set('Accept', 'application/json')
157
158   if (field) req.query({ field })
159
160   return req.expect(200)
161             .expect('Content-Type', /json/)
162 }
163
164 function searchVideoWithPagination (url: string, search: string, field: string, start: number, count: number, sort?: string) {
165   const path = '/api/v1/videos'
166
167   const req = request(url)
168                 .get(path + '/search/' + search)
169                 .query({ start })
170                 .query({ count })
171                 .query({ field })
172
173   if (sort) req.query({ sort })
174
175   return req.set('Accept', 'application/json')
176             .expect(200)
177             .expect('Content-Type', /json/)
178 }
179
180 function searchVideoWithSort (url: string, search: string, sort: string) {
181   const path = '/api/v1/videos'
182
183   return request(url)
184           .get(path + '/search/' + search)
185           .query({ sort })
186           .set('Accept', 'application/json')
187           .expect(200)
188           .expect('Content-Type', /json/)
189 }
190
191 async function testVideoImage (url: string, imageName: string, imagePath: string) {
192   // Don't test images if the node env is not set
193   // Because we need a special ffmpeg version for this test
194   if (process.env['NODE_TEST_IMAGE']) {
195     const res = await request(url)
196                         .get(imagePath)
197                         .expect(200)
198
199     const data = await readFilePromise(join(__dirname, '..', 'api', 'fixtures', imageName + '.jpg'))
200
201     return data.equals(res.body)
202   } else {
203     console.log('Do not test images. Enable it by setting NODE_TEST_IMAGE env variable.')
204     return true
205   }
206 }
207
208 async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = 204) {
209   const path = '/api/v1/videos/upload'
210   let defaultChannelId = '1'
211
212   try {
213     const res = await getMyUserInformation(url, accessToken)
214     defaultChannelId = res.body.videoChannels[0].id
215   } catch (e) { /* empty */ }
216
217   // Default attributes
218   let attributes = {
219     name: 'my super video',
220     category: 5,
221     licence: 4,
222     language: 3,
223     channelId: defaultChannelId,
224     nsfw: true,
225     description: 'my super description',
226     tags: [ 'tag' ],
227     privacy: VideoPrivacy.PUBLIC,
228     fixture: 'video_short.webm'
229   }
230   attributes = Object.assign(attributes, videoAttributesArg)
231
232   const req = request(url)
233               .post(path)
234               .set('Accept', 'application/json')
235               .set('Authorization', 'Bearer ' + accessToken)
236               .field('name', attributes.name)
237               .field('category', attributes.category.toString())
238               .field('licence', attributes.licence.toString())
239               .field('nsfw', JSON.stringify(attributes.nsfw))
240               .field('description', attributes.description)
241               .field('privacy', attributes.privacy.toString())
242               .field('channelId', attributes.channelId)
243
244   if (attributes.language !== undefined) {
245     req.field('language', attributes.language.toString())
246   }
247
248   for (let i = 0; i < attributes.tags.length; i++) {
249     req.field('tags[' + i + ']', attributes.tags[i])
250   }
251
252   let filePath = ''
253   if (isAbsolute(attributes.fixture)) {
254     filePath = attributes.fixture
255   } else {
256     filePath = join(__dirname, '..', 'api', 'fixtures', attributes.fixture)
257   }
258
259   return req.attach('videofile', filePath)
260             .expect(specialStatus)
261 }
262
263 function updateVideo (url: string, accessToken: string, id: number, attributes: VideoAttributes, specialStatus = 204) {
264   const path = '/api/v1/videos/' + id
265   const body = {}
266
267   if (attributes.name) body['name'] = attributes.name
268   if (attributes.category) body['category'] = attributes.category
269   if (attributes.licence) body['licence'] = attributes.licence
270   if (attributes.language) body['language'] = attributes.language
271   if (attributes.nsfw) body['nsfw'] = attributes.nsfw
272   if (attributes.description) body['description'] = attributes.description
273   if (attributes.tags) body['tags'] = attributes.tags
274   if (attributes.privacy) body['privacy'] = attributes.privacy
275
276   return request(url)
277           .put(path)
278           .send(body)
279           .set('Accept', 'application/json')
280           .set('Authorization', 'Bearer ' + accessToken)
281           .expect(specialStatus)
282 }
283
284 function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
285   const path = '/api/v1/videos/' + id + '/rate'
286
287   return request(url)
288           .put(path)
289           .set('Accept', 'application/json')
290           .set('Authorization', 'Bearer ' + accessToken)
291           .send({ rating })
292           .expect(specialStatus)
293 }
294
295 function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
296   return new Promise<any>((res, rej) => {
297     const torrentName = videoUUID + '-' + resolution + '.torrent'
298     const torrentPath = join(__dirname, '..', '..', '..', 'test' + server.serverNumber, 'torrents', torrentName)
299     readFile(torrentPath, (err, data) => {
300       if (err) return rej(err)
301
302       return res(parseTorrent(data))
303     })
304   })
305 }
306
307 // ---------------------------------------------------------------------------
308
309 export {
310   getVideoDescription,
311   getVideoCategories,
312   getVideoLicences,
313   getVideoPrivacies,
314   getVideoLanguages,
315   getAllVideosListBy,
316   getMyVideos,
317   getVideo,
318   getVideoWithToken,
319   getVideosList,
320   getVideosListPagination,
321   getVideosListSort,
322   removeVideo,
323   searchVideo,
324   searchVideoWithPagination,
325   searchVideoWithSort,
326   testVideoImage,
327   uploadVideo,
328   updateVideo,
329   rateVideo,
330   parseTorrentVideo
331 }