aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/config.ts8
-rw-r--r--server/controllers/api/users.ts2
-rw-r--r--server/controllers/api/videos/import.ts10
-rw-r--r--server/initializers/constants.ts5
-rw-r--r--server/initializers/migrations/0245-import-magnet.ts42
-rw-r--r--server/lib/job-queue/handlers/video-import.ts9
-rw-r--r--server/middlewares/validators/config.ts1
-rw-r--r--server/middlewares/validators/video-imports.ts15
-rw-r--r--server/models/account/user.ts2
-rw-r--r--server/models/video/video-import.ts83
-rw-r--r--server/tests/api/check-params/config.ts3
-rw-r--r--server/tests/api/server/config.ts5
-rw-r--r--server/tests/utils/server/config.ts3
13 files changed, 84 insertions, 104 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 950a1498e..6f05c33db 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -9,7 +9,7 @@ import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers'
9import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' 9import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
10import { customConfigUpdateValidator } from '../../middlewares/validators/config' 10import { customConfigUpdateValidator } from '../../middlewares/validators/config'
11import { ClientHtml } from '../../lib/client-html' 11import { ClientHtml } from '../../lib/client-html'
12import { CustomConfigAuditView, auditLoggerFactory } from '../../helpers/audit-logger' 12import { auditLoggerFactory, CustomConfigAuditView } from '../../helpers/audit-logger'
13 13
14const packageJSON = require('../../../../package.json') 14const packageJSON = require('../../../../package.json')
15const configRouter = express.Router() 15const configRouter = express.Router()
@@ -69,6 +69,9 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
69 videos: { 69 videos: {
70 http: { 70 http: {
71 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED 71 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
72 },
73 torrent: {
74 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
72 } 75 }
73 } 76 }
74 }, 77 },
@@ -237,6 +240,9 @@ function customConfig (): CustomConfig {
237 videos: { 240 videos: {
238 http: { 241 http: {
239 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED 242 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
243 },
244 torrent: {
245 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
240 } 246 }
241 } 247 }
242 } 248 }
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts
index 879ba3f91..36bf0e0fe 100644
--- a/server/controllers/api/users.ts
+++ b/server/controllers/api/users.ts
@@ -196,7 +196,7 @@ async function getUserVideos (req: express.Request, res: express.Response, next:
196async function getUserVideoImports (req: express.Request, res: express.Response, next: express.NextFunction) { 196async function getUserVideoImports (req: express.Request, res: express.Response, next: express.NextFunction) {
197 const user = res.locals.oauth.token.User as UserModel 197 const user = res.locals.oauth.token.User as UserModel
198 const resultList = await VideoImportModel.listUserVideoImportsForApi( 198 const resultList = await VideoImportModel.listUserVideoImportsForApi(
199 user.Account.id, 199 user.id,
200 req.query.start as number, 200 req.query.start as number,
201 req.query.count as number, 201 req.query.count as number,
202 req.query.sort 202 req.query.sort
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts
index df151e79d..94dafcdbd 100644
--- a/server/controllers/api/videos/import.ts
+++ b/server/controllers/api/videos/import.ts
@@ -61,12 +61,13 @@ export {
61function addVideoImport (req: express.Request, res: express.Response) { 61function addVideoImport (req: express.Request, res: express.Response) {
62 if (req.body.targetUrl) return addYoutubeDLImport(req, res) 62 if (req.body.targetUrl) return addYoutubeDLImport(req, res)
63 63
64 const file = req.files['torrentfile'][0] 64 const file = req.files && req.files['torrentfile'] ? req.files['torrentfile'][0] : undefined
65 if (req.body.magnetUri || file) return addTorrentImport(req, res, file) 65 if (req.body.magnetUri || file) return addTorrentImport(req, res, file)
66} 66}
67 67
68async function addTorrentImport (req: express.Request, res: express.Response, torrentfile: Express.Multer.File) { 68async function addTorrentImport (req: express.Request, res: express.Response, torrentfile: Express.Multer.File) {
69 const body: VideoImportCreate = req.body 69 const body: VideoImportCreate = req.body
70 const user = res.locals.oauth.token.User
70 71
71 let videoName: string 72 let videoName: string
72 let torrentName: string 73 let torrentName: string
@@ -100,7 +101,8 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
100 const videoImportAttributes = { 101 const videoImportAttributes = {
101 magnetUri, 102 magnetUri,
102 torrentName, 103 torrentName,
103 state: VideoImportState.PENDING 104 state: VideoImportState.PENDING,
105 userId: user.id
104 } 106 }
105 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes) 107 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes)
106 108
@@ -120,6 +122,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
120async function addYoutubeDLImport (req: express.Request, res: express.Response) { 122async function addYoutubeDLImport (req: express.Request, res: express.Response) {
121 const body: VideoImportCreate = req.body 123 const body: VideoImportCreate = req.body
122 const targetUrl = body.targetUrl 124 const targetUrl = body.targetUrl
125 const user = res.locals.oauth.token.User
123 126
124 let youtubeDLInfo: YoutubeDLInfo 127 let youtubeDLInfo: YoutubeDLInfo
125 try { 128 try {
@@ -140,7 +143,8 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
140 const tags = body.tags || youtubeDLInfo.tags 143 const tags = body.tags || youtubeDLInfo.tags
141 const videoImportAttributes = { 144 const videoImportAttributes = {
142 targetUrl, 145 targetUrl,
143 state: VideoImportState.PENDING 146 state: VideoImportState.PENDING,
147 userId: user.id
144 } 148 }
145 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes) 149 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes)
146 150
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index cf7cd3d74..80eb3f1e7 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -15,7 +15,7 @@ let config: IConfig = require('config')
15 15
16// --------------------------------------------------------------------------- 16// ---------------------------------------------------------------------------
17 17
18const LAST_MIGRATION_VERSION = 245 18const LAST_MIGRATION_VERSION = 240
19 19
20// --------------------------------------------------------------------------- 20// ---------------------------------------------------------------------------
21 21
@@ -211,6 +211,9 @@ const CONFIG = {
211 VIDEOS: { 211 VIDEOS: {
212 HTTP: { 212 HTTP: {
213 get ENABLED () { return config.get<boolean>('import.videos.http.enabled') } 213 get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }
214 },
215 TORRENT: {
216 get ENABLED () { return config.get<boolean>('import.videos.torrent.enabled') }
214 } 217 }
215 } 218 }
216 }, 219 },
diff --git a/server/initializers/migrations/0245-import-magnet.ts b/server/initializers/migrations/0245-import-magnet.ts
deleted file mode 100644
index 87603b006..000000000
--- a/server/initializers/migrations/0245-import-magnet.ts
+++ /dev/null
@@ -1,42 +0,0 @@
1import * as Sequelize from 'sequelize'
2import { Migration } from '../../models/migrations'
3import { CONSTRAINTS_FIELDS } from '../index'
4
5async function up (utils: {
6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize
9}): Promise<any> {
10 {
11 const data = {
12 type: Sequelize.STRING,
13 allowNull: true,
14 defaultValue: null
15 } as Migration.String
16 await utils.queryInterface.changeColumn('videoImport', 'targetUrl', data)
17 }
18
19 {
20 const data = {
21 type: Sequelize.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max),
22 allowNull: true,
23 defaultValue: null
24 }
25 await utils.queryInterface.addColumn('videoImport', 'magnetUri', data)
26 }
27
28 {
29 const data = {
30 type: Sequelize.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_NAME.max),
31 allowNull: true,
32 defaultValue: null
33 }
34 await utils.queryInterface.addColumn('videoImport', 'torrentName', data)
35 }
36}
37
38function down (options) {
39 throw new Error('Not implemented.')
40}
41
42export { up, down }
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index fd61aecad..28a03d19e 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -114,16 +114,21 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide
114 tempVideoPath = await downloader() 114 tempVideoPath = await downloader()
115 115
116 // Get information about this video 116 // Get information about this video
117 const { size } = await statPromise(tempVideoPath)
118 const isAble = await videoImport.User.isAbleToUploadVideo({ size })
119 if (isAble === false) {
120 throw new Error('The user video quota is exceeded with this video to import.')
121 }
122
117 const { videoFileResolution } = await getVideoFileResolution(tempVideoPath) 123 const { videoFileResolution } = await getVideoFileResolution(tempVideoPath)
118 const fps = await getVideoFileFPS(tempVideoPath) 124 const fps = await getVideoFileFPS(tempVideoPath)
119 const stats = await statPromise(tempVideoPath)
120 const duration = await getDurationFromVideoFile(tempVideoPath) 125 const duration = await getDurationFromVideoFile(tempVideoPath)
121 126
122 // Create video file object in database 127 // Create video file object in database
123 const videoFileData = { 128 const videoFileData = {
124 extname: extname(tempVideoPath), 129 extname: extname(tempVideoPath),
125 resolution: videoFileResolution, 130 resolution: videoFileResolution,
126 size: stats.size, 131 size,
127 fps, 132 fps,
128 videoId: videoImport.videoId 133 videoId: videoImport.videoId
129 } 134 }
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts
index 9d303eee2..f3f257d57 100644
--- a/server/middlewares/validators/config.ts
+++ b/server/middlewares/validators/config.ts
@@ -25,6 +25,7 @@ const customConfigUpdateValidator = [
25 body('transcoding.resolutions.720p').isBoolean().withMessage('Should have a valid transcoding 720p resolution enabled boolean'), 25 body('transcoding.resolutions.720p').isBoolean().withMessage('Should have a valid transcoding 720p resolution enabled boolean'),
26 body('transcoding.resolutions.1080p').isBoolean().withMessage('Should have a valid transcoding 1080p resolution enabled boolean'), 26 body('transcoding.resolutions.1080p').isBoolean().withMessage('Should have a valid transcoding 1080p resolution enabled boolean'),
27 body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), 27 body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'),
28 body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'),
28 29
29 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 30 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
30 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) 31 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body })
diff --git a/server/middlewares/validators/video-imports.ts b/server/middlewares/validators/video-imports.ts
index c03cf2e4d..9ac739101 100644
--- a/server/middlewares/validators/video-imports.ts
+++ b/server/middlewares/validators/video-imports.ts
@@ -33,21 +33,28 @@ const videoImportAddValidator = getCommonVideoAttributes().concat([
33 logger.debug('Checking videoImportAddValidator parameters', { parameters: req.body }) 33 logger.debug('Checking videoImportAddValidator parameters', { parameters: req.body })
34 34
35 const user = res.locals.oauth.token.User 35 const user = res.locals.oauth.token.User
36 const torrentFile = req.files && req.files['torrentfile'] ? req.files['torrentfile'][0] : undefined
36 37
37 if (areValidationErrors(req, res)) return cleanUpReqFiles(req) 38 if (areValidationErrors(req, res)) return cleanUpReqFiles(req)
38 39
39 if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true) { 40 if (req.body.targetUrl && CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true) {
40 cleanUpReqFiles(req) 41 cleanUpReqFiles(req)
41 return res.status(409) 42 return res.status(409)
42 .json({ error: 'Import is not enabled on this instance.' }) 43 .json({ error: 'HTTP import is not enabled on this instance.' })
43 .end() 44 .end()
44 } 45 }
45 46
47 if (CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED !== true && (req.body.magnetUri || torrentFile)) {
48 cleanUpReqFiles(req)
49 return res.status(409)
50 .json({ error: 'Torrent/magnet URI import is not enabled on this instance.' })
51 .end()
52 }
53
46 if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) 54 if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
47 55
48 // Check we have at least 1 required param 56 // Check we have at least 1 required param
49 const file = req.files['torrentfile'][0] 57 if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) {
50 if (!req.body.targetUrl && !req.body.magnetUri && !file) {
51 cleanUpReqFiles(req) 58 cleanUpReqFiles(req)
52 59
53 return res.status(400) 60 return res.status(400)
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 1165285ea..1b1fc5ee8 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -295,7 +295,7 @@ export class UserModel extends Model<UserModel> {
295 return json 295 return json
296 } 296 }
297 297
298 isAbleToUploadVideo (videoFile: Express.Multer.File) { 298 isAbleToUploadVideo (videoFile: { size: number }) {
299 if (this.videoQuota === -1) return Promise.resolve(true) 299 if (this.videoQuota === -1) return Promise.resolve(true)
300 300
301 return UserModel.getOriginalVideoFileTotalFromUser(this) 301 return UserModel.getOriginalVideoFileTotalFromUser(this)
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts
index d6c02e5ac..b794d8324 100644
--- a/server/models/video/video-import.ts
+++ b/server/models/video/video-import.ts
@@ -15,34 +15,21 @@ import {
15} from 'sequelize-typescript' 15} from 'sequelize-typescript'
16import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers' 16import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers'
17import { getSort, throwIfNotValid } from '../utils' 17import { getSort, throwIfNotValid } from '../utils'
18import { VideoModel } from './video' 18import { ScopeNames as VideoModelScopeNames, VideoModel } from './video'
19import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' 19import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports'
20import { VideoImport, VideoImportState } from '../../../shared' 20import { VideoImport, VideoImportState } from '../../../shared'
21import { VideoChannelModel } from './video-channel'
22import { AccountModel } from '../account/account'
23import { TagModel } from './tag'
24import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' 21import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
22import { UserModel } from '../account/user'
25 23
26@DefaultScope({ 24@DefaultScope({
27 include: [ 25 include: [
28 { 26 {
29 model: () => VideoModel, 27 model: () => UserModel.unscoped(),
30 required: false, 28 required: true
31 include: [ 29 },
32 { 30 {
33 model: () => VideoChannelModel, 31 model: () => VideoModel.scope([ VideoModelScopeNames.WITH_ACCOUNT_DETAILS, VideoModelScopeNames.WITH_TAGS]),
34 required: true, 32 required: false
35 include: [
36 {
37 model: () => AccountModel,
38 required: true
39 }
40 ]
41 },
42 {
43 model: () => TagModel
44 }
45 ]
46 } 33 }
47 ] 34 ]
48}) 35})
@@ -53,6 +40,9 @@ import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
53 { 40 {
54 fields: [ 'videoId' ], 41 fields: [ 'videoId' ],
55 unique: true 42 unique: true
43 },
44 {
45 fields: [ 'userId' ]
56 } 46 }
57 ] 47 ]
58}) 48})
@@ -91,6 +81,18 @@ export class VideoImportModel extends Model<VideoImportModel> {
91 @Column(DataType.TEXT) 81 @Column(DataType.TEXT)
92 error: string 82 error: string
93 83
84 @ForeignKey(() => UserModel)
85 @Column
86 userId: number
87
88 @BelongsTo(() => UserModel, {
89 foreignKey: {
90 allowNull: false
91 },
92 onDelete: 'cascade'
93 })
94 User: UserModel
95
94 @ForeignKey(() => VideoModel) 96 @ForeignKey(() => VideoModel)
95 @Column 97 @Column
96 videoId: number 98 videoId: number
@@ -116,41 +118,24 @@ export class VideoImportModel extends Model<VideoImportModel> {
116 return VideoImportModel.findById(id) 118 return VideoImportModel.findById(id)
117 } 119 }
118 120
119 static listUserVideoImportsForApi (accountId: number, start: number, count: number, sort: string) { 121 static listUserVideoImportsForApi (userId: number, start: number, count: number, sort: string) {
120 const query = { 122 const query = {
121 distinct: true, 123 distinct: true,
122 offset: start,
123 limit: count,
124 order: getSort(sort),
125 include: [ 124 include: [
126 { 125 {
127 model: VideoModel, 126 model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query
128 required: false, 127 required: true
129 include: [
130 {
131 model: VideoChannelModel,
132 required: true,
133 include: [
134 {
135 model: AccountModel,
136 required: true,
137 where: {
138 id: accountId
139 }
140 }
141 ]
142 },
143 {
144 model: TagModel,
145 required: false
146 }
147 ]
148 } 128 }
149 ] 129 ],
130 offset: start,
131 limit: count,
132 order: getSort(sort),
133 where: {
134 userId
135 }
150 } 136 }
151 137
152 return VideoImportModel.unscoped() 138 return VideoImportModel.findAndCountAll(query)
153 .findAndCountAll(query)
154 .then(({ rows, count }) => { 139 .then(({ rows, count }) => {
155 return { 140 return {
156 data: rows, 141 data: rows,
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index 2742e26de..b26dfa252 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -65,6 +65,9 @@ describe('Test config API validators', function () {
65 videos: { 65 videos: {
66 http: { 66 http: {
67 enabled: false 67 enabled: false
68 },
69 torrent: {
70 enabled: false
68 } 71 }
69 } 72 }
70 } 73 }
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index b65061a5d..f9805b6ea 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -45,6 +45,7 @@ function checkInitialConfig (data: CustomConfig) {
45 expect(data.transcoding.resolutions['720p']).to.be.true 45 expect(data.transcoding.resolutions['720p']).to.be.true
46 expect(data.transcoding.resolutions['1080p']).to.be.true 46 expect(data.transcoding.resolutions['1080p']).to.be.true
47 expect(data.import.videos.http.enabled).to.be.true 47 expect(data.import.videos.http.enabled).to.be.true
48 expect(data.import.videos.torrent.enabled).to.be.true
48} 49}
49 50
50function checkUpdatedConfig (data: CustomConfig) { 51function checkUpdatedConfig (data: CustomConfig) {
@@ -72,6 +73,7 @@ function checkUpdatedConfig (data: CustomConfig) {
72 expect(data.transcoding.resolutions['720p']).to.be.false 73 expect(data.transcoding.resolutions['720p']).to.be.false
73 expect(data.transcoding.resolutions['1080p']).to.be.false 74 expect(data.transcoding.resolutions['1080p']).to.be.false
74 expect(data.import.videos.http.enabled).to.be.false 75 expect(data.import.videos.http.enabled).to.be.false
76 expect(data.import.videos.torrent.enabled).to.be.false
75} 77}
76 78
77describe('Test config', function () { 79describe('Test config', function () {
@@ -167,6 +169,9 @@ describe('Test config', function () {
167 videos: { 169 videos: {
168 http: { 170 http: {
169 enabled: false 171 enabled: false
172 },
173 torrent: {
174 enabled: false
170 } 175 }
171 } 176 }
172 } 177 }
diff --git a/server/tests/utils/server/config.ts b/server/tests/utils/server/config.ts
index e21614282..d6ac3ef8a 100644
--- a/server/tests/utils/server/config.ts
+++ b/server/tests/utils/server/config.ts
@@ -97,6 +97,9 @@ function updateCustomSubConfig (url: string, token: string, newConfig: any) {
97 videos: { 97 videos: {
98 http: { 98 http: {
99 enabled: false 99 enabled: false
100 },
101 torrent: {
102 enabled: false
100 } 103 }
101 } 104 }
102 } 105 }