aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/api/server/follows.ts6
-rw-r--r--server/helpers/custom-validators/activitypub/videos.ts30
-rw-r--r--server/helpers/custom-validators/videos.ts15
-rw-r--r--server/lib/activitypub/send-request.ts7
-rw-r--r--server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts3
-rw-r--r--server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts3
-rw-r--r--server/lib/jobs/job-scheduler.ts4
-rw-r--r--server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts2
-rw-r--r--server/models/account/account-follow-interface.ts4
-rw-r--r--server/models/account/account-follow.ts24
-rw-r--r--server/models/account/account.ts1
-rw-r--r--server/models/video/video.ts4
12 files changed, 59 insertions, 44 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index c9775ad21..ac8ea87f9 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -108,7 +108,11 @@ async function follow (req: express.Request, res: express.Response, next: expres
108 tasks.push(p) 108 tasks.push(p)
109 } 109 }
110 110
111 await Promise.all(tasks) 111 // Don't make the client wait the tasks
112 Promise.all(tasks)
113 .catch(err => {
114 logger.error('Error in follow.', err)
115 })
112 116
113 return res.status(204).end() 117 return res.status(204).end()
114} 118}
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts
index c9ecf1f3d..a46757397 100644
--- a/server/helpers/custom-validators/activitypub/videos.ts
+++ b/server/helpers/custom-validators/activitypub/videos.ts
@@ -1,20 +1,17 @@
1import * as validator from 'validator' 1import * as validator from 'validator'
2 2import { ACTIVITY_PUB } from '../../../initializers'
3import { 3import { exists, isDateValid, isUUIDValid } from '../misc'
4 ACTIVITY_PUB 4import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
5} from '../../../initializers'
6import { isDateValid, isUUIDValid } from '../misc'
7import { 5import {
8 isVideoViewsValid,
9 isVideoNSFWValid,
10 isVideoTruncatedDescriptionValid,
11 isVideoDurationValid, 6 isVideoDurationValid,
12 isVideoNameValid, 7 isVideoNameValid,
8 isVideoNSFWValid,
13 isVideoTagValid, 9 isVideoTagValid,
14 isVideoUrlValid 10 isVideoTruncatedDescriptionValid,
11 isVideoUrlValid,
12 isVideoViewsValid
15} from '../videos' 13} from '../videos'
16import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels' 14import { isBaseActivityValid } from './misc'
17import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
18 15
19function isVideoTorrentAddActivityValid (activity: any) { 16function isVideoTorrentAddActivityValid (activity: any) {
20 return isBaseActivityValid(activity, 'Add') && 17 return isBaseActivityValid(activity, 'Add') &&
@@ -30,10 +27,19 @@ function isVideoTorrentDeleteActivityValid (activity: any) {
30 return isBaseActivityValid(activity, 'Delete') 27 return isBaseActivityValid(activity, 'Delete')
31} 28}
32 29
30function isActivityPubVideoDurationValid (value: string) {
31 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
32 return exists(value) &&
33 typeof value === 'string' &&
34 value.startsWith('PT') &&
35 value.endsWith('S') &&
36 isVideoDurationValid(value.replace(/[^0-9]+/, ''))
37}
38
33function isVideoTorrentObjectValid (video: any) { 39function isVideoTorrentObjectValid (video: any) {
34 return video.type === 'Video' && 40 return video.type === 'Video' &&
35 isVideoNameValid(video.name) && 41 isVideoNameValid(video.name) &&
36 isVideoDurationValid(video.duration) && 42 isActivityPubVideoDurationValid(video.duration) &&
37 isUUIDValid(video.uuid) && 43 isUUIDValid(video.uuid) &&
38 setValidRemoteTags(video) && 44 setValidRemoteTags(video) &&
39 isRemoteIdentifierValid(video.category) && 45 isRemoteIdentifierValid(video.category) &&
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts
index 1505632da..c97c9a2ad 100644
--- a/server/helpers/custom-validators/videos.ts
+++ b/server/helpers/custom-validators/videos.ts
@@ -69,6 +69,10 @@ function isVideoNSFWValid (value: any) {
69 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value)) 69 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
70} 70}
71 71
72function isVideoDurationValid (value: string) {
73 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
74}
75
72function isVideoTruncatedDescriptionValid (value: string) { 76function isVideoTruncatedDescriptionValid (value: string) {
73 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION) 77 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
74} 78}
@@ -77,15 +81,6 @@ function isVideoDescriptionValid (value: string) {
77 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION) 81 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
78} 82}
79 83
80function isVideoDurationValid (value: string) {
81 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
82 return exists(value) &&
83 typeof value === 'string' &&
84 value.startsWith('PT') &&
85 value.endsWith('S') &&
86 validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
87}
88
89function isVideoNameValid (value: string) { 84function isVideoNameValid (value: string) {
90 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME) 85 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
91} 86}
@@ -197,7 +192,6 @@ export {
197 isVideoNSFWValid, 192 isVideoNSFWValid,
198 isVideoTruncatedDescriptionValid, 193 isVideoTruncatedDescriptionValid,
199 isVideoDescriptionValid, 194 isVideoDescriptionValid,
200 isVideoDurationValid,
201 isVideoFileInfoHashValid, 195 isVideoFileInfoHashValid,
202 isVideoNameValid, 196 isVideoNameValid,
203 isVideoTagsValid, 197 isVideoTagsValid,
@@ -214,6 +208,7 @@ export {
214 isVideoFileSizeValid, 208 isVideoFileSizeValid,
215 isVideoPrivacyValid, 209 isVideoPrivacyValid,
216 isRemoteVideoPrivacyValid, 210 isRemoteVideoPrivacyValid,
211 isVideoDurationValid,
217 isVideoFileResolutionValid, 212 isVideoFileResolutionValid,
218 checkVideoExists, 213 checkVideoExists,
219 isVideoTagValid, 214 isVideoTagValid,
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts
index 1a6cebc03..1dad51828 100644
--- a/server/lib/activitypub/send-request.ts
+++ b/server/lib/activitypub/send-request.ts
@@ -11,6 +11,7 @@ import { signObject, activityPubContextify } from '../../helpers'
11import { Activity } from '../../../shared' 11import { Activity } from '../../../shared'
12import { VideoAbuseInstance } from '../../models/video/video-abuse-interface' 12import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
13import { getActivityPubUrl } from '../../helpers/activitypub' 13import { getActivityPubUrl } from '../../helpers/activitypub'
14import { logger } from '../../helpers/logger'
14 15
15async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { 16async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
16 const videoChannelObject = videoChannel.toActivityPubObject() 17 const videoChannelObject = videoChannel.toActivityPubObject()
@@ -100,7 +101,11 @@ export {
100// --------------------------------------------------------------------------- 101// ---------------------------------------------------------------------------
101 102
102async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { 103async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
103 const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id, 0) 104 const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id)
105 if (result.data.length === 0) {
106 logger.info('Not broadcast because of 0 followers.')
107 return
108 }
104 109
105 const jobPayload = { 110 const jobPayload = {
106 uris: result.data, 111 uris: result.data,
diff --git a/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts b/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
index 2f1d9ee92..ccb008e4d 100644
--- a/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
+++ b/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
@@ -22,8 +22,9 @@ function onError (err: Error, jobId: number) {
22 return Promise.resolve() 22 return Promise.resolve()
23} 23}
24 24
25async function onSuccess (jobId: number) { 25function onSuccess (jobId: number) {
26 logger.info('Job %d is a success.', jobId) 26 logger.info('Job %d is a success.', jobId)
27 return Promise.resolve()
27} 28}
28 29
29// --------------------------------------------------------------------------- 30// ---------------------------------------------------------------------------
diff --git a/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts b/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
index 3a1a7fabf..9e4e73891 100644
--- a/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
+++ b/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
@@ -20,8 +20,9 @@ function onError (err: Error, jobId: number) {
20 return Promise.resolve() 20 return Promise.resolve()
21} 21}
22 22
23async function onSuccess (jobId: number) { 23function onSuccess (jobId: number) {
24 logger.info('Job %d is a success.', jobId) 24 logger.info('Job %d is a success.', jobId)
25 return Promise.resolve()
25} 26}
26 27
27// --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
diff --git a/server/lib/jobs/job-scheduler.ts b/server/lib/jobs/job-scheduler.ts
index b25bb7ab3..73c440279 100644
--- a/server/lib/jobs/job-scheduler.ts
+++ b/server/lib/jobs/job-scheduler.ts
@@ -9,7 +9,7 @@ import { error } from 'util'
9export interface JobHandler<P, T> { 9export interface JobHandler<P, T> {
10 process (data: object, jobId: number): Promise<T> 10 process (data: object, jobId: number): Promise<T>
11 onError (err: Error, jobId: number) 11 onError (err: Error, jobId: number)
12 onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>) 12 onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>): Promise<any>
13} 13}
14type JobQueueCallback = (err: Error) => void 14type JobQueueCallback = (err: Error) => void
15 15
@@ -127,7 +127,7 @@ class JobScheduler<P, T> {
127 127
128 try { 128 try {
129 await job.save() 129 await job.save()
130 jobHandler.onSuccess(job.id, jobResult, this) 130 await jobHandler.onSuccess(job.id, jobResult, this)
131 } catch (err) { 131 } catch (err) {
132 this.cannotSaveJobError(err) 132 this.cannotSaveJobError(err)
133 } 133 }
diff --git a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
index d3ee886e7..f6d9627a5 100644
--- a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
+++ b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
@@ -39,8 +39,8 @@ async function onSuccess (jobId: number, video: VideoInstance, jobScheduler: Job
39 await sendAddVideo(video, undefined) 39 await sendAddVideo(video, undefined)
40 40
41 const originalFileHeight = await videoDatabase.getOriginalFileHeight() 41 const originalFileHeight = await videoDatabase.getOriginalFileHeight()
42 // Create transcoding jobs if there are enabled resolutions
43 42
43 // Create transcoding jobs if there are enabled resolutions
44 const resolutionsEnabled = computeResolutionsToTranscode(originalFileHeight) 44 const resolutionsEnabled = computeResolutionsToTranscode(originalFileHeight)
45 logger.info( 45 logger.info(
46 'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, originalFileHeight, 46 'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, originalFileHeight,
diff --git a/server/models/account/account-follow-interface.ts b/server/models/account/account-follow-interface.ts
index 413dad190..54baf45ed 100644
--- a/server/models/account/account-follow-interface.ts
+++ b/server/models/account/account-follow-interface.ts
@@ -10,8 +10,8 @@ export namespace AccountFollowMethods {
10 export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > 10 export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
11 export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > 11 export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
12 12
13 export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > 13 export type ListAcceptedFollowerUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
14 export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > 14 export type ListAcceptedFollowingUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
15} 15}
16 16
17export interface AccountFollowClass { 17export interface AccountFollowClass {
diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts
index c940d7cd4..f457e43e9 100644
--- a/server/models/account/account-follow.ts
+++ b/server/models/account/account-follow.ts
@@ -146,17 +146,17 @@ listFollowersForApi = function (id: number, start: number, count: number, sort:
146 }) 146 })
147} 147}
148 148
149listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { 149listAcceptedFollowerUrlsForApi = function (accountId: number, start?: number, count?: number) {
150 return createListAcceptedFollowForApiQuery('followers', id, start, count) 150 return createListAcceptedFollowForApiQuery('followers', accountId, start, count)
151} 151}
152 152
153listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { 153listAcceptedFollowingUrlsForApi = function (accountId: number, start?: number, count?: number) {
154 return createListAcceptedFollowForApiQuery('following', id, start, count) 154 return createListAcceptedFollowForApiQuery('following', accountId, start, count)
155} 155}
156 156
157// ------------------------------ UTILS ------------------------------ 157// ------------------------------ UTILS ------------------------------
158 158
159async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) { 159async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', accountId: number, start?: number, count?: number) {
160 let firstJoin: string 160 let firstJoin: string
161 let secondJoin: string 161 let secondJoin: string
162 162
@@ -168,20 +168,20 @@ async function createListAcceptedFollowForApiQuery (type: 'followers' | 'followi
168 secondJoin = 'targetAccountId' 168 secondJoin = 'targetAccountId'
169 } 169 }
170 170
171 const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ] 171 const selections = [ '"Follows"."url" AS "url"', 'COUNT(*) AS "total"' ]
172 const tasks: Promise<any>[] = [] 172 const tasks: Promise<any>[] = []
173 173
174 for (const selection of selections) { 174 for (const selection of selections) {
175 let query = 'SELECT ' + selection + ' FROM "Account" ' + 175 let query = 'SELECT ' + selection + ' FROM "Accounts" ' +
176 'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' + 176 'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' +
177 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' + 177 'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' +
178 'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' + 178 'WHERE "Accounts"."id" = $accountId AND "AccountFollows"."state" = \'accepted\' '
179 'LIMIT ' + start
180 179
180 if (start !== undefined) query += 'LIMIT ' + start
181 if (count !== undefined) query += ', ' + count 181 if (count !== undefined) query += ', ' + count
182 182
183 const options = { 183 const options = {
184 bind: { id }, 184 bind: { accountId },
185 type: Sequelize.QueryTypes.SELECT 185 type: Sequelize.QueryTypes.SELECT
186 } 186 }
187 tasks.push(AccountFollow['sequelize'].query(query, options)) 187 tasks.push(AccountFollow['sequelize'].query(query, options))
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 464105261..84461a2eb 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -263,6 +263,7 @@ function associate (models) {
263 name: 'targetAccountId', 263 name: 'targetAccountId',
264 allowNull: false 264 allowNull: false
265 }, 265 },
266 as: 'followers',
266 onDelete: 'cascade' 267 onDelete: 'cascade'
267 }) 268 })
268} 269}
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 86800fb88..b00081f25 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -329,7 +329,7 @@ function associate (models) {
329 onDelete: 'cascade' 329 onDelete: 'cascade'
330 }) 330 })
331 331
332 Video.belongsTo(models.VideoChannel, { 332 Video.belongsTo(models.Video, {
333 foreignKey: { 333 foreignKey: {
334 name: 'parentId', 334 name: 'parentId',
335 allowNull: true 335 allowNull: true
@@ -825,9 +825,11 @@ listForApi = function (start: number, count: number, sort: string) {
825 include: [ 825 include: [
826 { 826 {
827 model: Video['sequelize'].models.VideoChannel, 827 model: Video['sequelize'].models.VideoChannel,
828 required: true,
828 include: [ 829 include: [
829 { 830 {
830 model: Video['sequelize'].models.Account, 831 model: Video['sequelize'].models.Account,
832 required: true,
831 include: [ 833 include: [
832 { 834 {
833 model: Video['sequelize'].models.Server, 835 model: Video['sequelize'].models.Server,