diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/server/follows.ts | 6 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/videos.ts | 30 | ||||
-rw-r--r-- | server/helpers/custom-validators/videos.ts | 15 | ||||
-rw-r--r-- | server/lib/activitypub/send-request.ts | 7 | ||||
-rw-r--r-- | server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts | 3 | ||||
-rw-r--r-- | server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts | 3 | ||||
-rw-r--r-- | server/lib/jobs/job-scheduler.ts | 4 | ||||
-rw-r--r-- | server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts | 2 | ||||
-rw-r--r-- | server/models/account/account-follow-interface.ts | 4 | ||||
-rw-r--r-- | server/models/account/account-follow.ts | 24 | ||||
-rw-r--r-- | server/models/account/account.ts | 1 | ||||
-rw-r--r-- | server/models/video/video.ts | 4 |
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 @@ | |||
1 | import * as validator from 'validator' | 1 | import * as validator from 'validator' |
2 | 2 | import { ACTIVITY_PUB } from '../../../initializers' | |
3 | import { | 3 | import { exists, isDateValid, isUUIDValid } from '../misc' |
4 | ACTIVITY_PUB | 4 | import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels' |
5 | } from '../../../initializers' | ||
6 | import { isDateValid, isUUIDValid } from '../misc' | ||
7 | import { | 5 | import { |
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' |
16 | import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels' | 14 | import { isBaseActivityValid } from './misc' |
17 | import { isActivityPubUrlValid, isBaseActivityValid } from './misc' | ||
18 | 15 | ||
19 | function isVideoTorrentAddActivityValid (activity: any) { | 16 | function 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 | ||
30 | function 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 | |||
33 | function isVideoTorrentObjectValid (video: any) { | 39 | function 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 | ||
72 | function isVideoDurationValid (value: string) { | ||
73 | return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION) | ||
74 | } | ||
75 | |||
72 | function isVideoTruncatedDescriptionValid (value: string) { | 76 | function 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 | ||
80 | function 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 | |||
89 | function isVideoNameValid (value: string) { | 84 | function 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' | |||
11 | import { Activity } from '../../../shared' | 11 | import { Activity } from '../../../shared' |
12 | import { VideoAbuseInstance } from '../../models/video/video-abuse-interface' | 12 | import { VideoAbuseInstance } from '../../models/video/video-abuse-interface' |
13 | import { getActivityPubUrl } from '../../helpers/activitypub' | 13 | import { getActivityPubUrl } from '../../helpers/activitypub' |
14 | import { logger } from '../../helpers/logger' | ||
14 | 15 | ||
15 | async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { | 16 | async 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 | ||
102 | async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { | 103 | async 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 | ||
25 | async function onSuccess (jobId: number) { | 25 | function 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 | ||
23 | async function onSuccess (jobId: number) { | 23 | function 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' | |||
9 | export interface JobHandler<P, T> { | 9 | export 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 | } |
14 | type JobQueueCallback = (err: Error) => void | 14 | type 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 | ||
17 | export interface AccountFollowClass { | 17 | export 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 | ||
149 | listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { | 149 | listAcceptedFollowerUrlsForApi = 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 | ||
153 | listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { | 153 | listAcceptedFollowingUrlsForApi = 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 | ||
159 | async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) { | 159 | async 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, |