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