diff options
author | Chocobozzz <me@florianbigard.com> | 2019-05-31 16:30:11 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-05-31 16:44:46 +0200 |
commit | 7d14d4d2ca82cc43c93b45bb1f90af975cfbf67c (patch) | |
tree | d2d2c9806dd1bf551ad39102149f514bca4c52eb /server | |
parent | 9977c128387f38dddd697b2e9a405dcea52407b7 (diff) | |
download | PeerTube-7d14d4d2ca82cc43c93b45bb1f90af975cfbf67c.tar.gz PeerTube-7d14d4d2ca82cc43c93b45bb1f90af975cfbf67c.tar.zst PeerTube-7d14d4d2ca82cc43c93b45bb1f90af975cfbf67c.zip |
Server: Bulk update videos support field
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/video-channel.ts | 26 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 1 | ||||
-rw-r--r-- | server/lib/video-channel.ts | 16 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-channels.ts | 16 | ||||
-rw-r--r-- | server/models/video/video.ts | 23 | ||||
-rw-r--r-- | server/tests/api/check-params/video-channels.ts | 12 | ||||
-rw-r--r-- | server/tests/api/videos/video-channels.ts | 42 |
7 files changed, 118 insertions, 18 deletions
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index c98a39be2..81a03a62b 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -19,7 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel' | |||
19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' | 19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' |
20 | import { sendUpdateActor } from '../../lib/activitypub/send' | 20 | import { sendUpdateActor } from '../../lib/activitypub/send' |
21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' | 21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' |
22 | import { createVideoChannel } from '../../lib/video-channel' | 22 | import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel' |
23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' | 23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
24 | import { setAsyncActorKeys } from '../../lib/activitypub' | 24 | import { setAsyncActorKeys } from '../../lib/activitypub' |
25 | import { AccountModel } from '../../models/account/account' | 25 | import { AccountModel } from '../../models/account/account' |
@@ -160,6 +160,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
160 | const videoChannelFieldsSave = videoChannelInstance.toJSON() | 160 | const videoChannelFieldsSave = videoChannelInstance.toJSON() |
161 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) | 161 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) |
162 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate | 162 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate |
163 | let doBulkVideoUpdate = false | ||
163 | 164 | ||
164 | try { | 165 | try { |
165 | await sequelizeTypescript.transaction(async t => { | 166 | await sequelizeTypescript.transaction(async t => { |
@@ -167,9 +168,18 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
167 | transaction: t | 168 | transaction: t |
168 | } | 169 | } |
169 | 170 | ||
170 | if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.displayName) | 171 | if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.name = videoChannelInfoToUpdate.displayName |
171 | if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) | 172 | if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.description = videoChannelInfoToUpdate.description |
172 | if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support) | 173 | |
174 | if (videoChannelInfoToUpdate.support !== undefined) { | ||
175 | const oldSupportField = videoChannelInstance.support | ||
176 | videoChannelInstance.support = videoChannelInfoToUpdate.support | ||
177 | |||
178 | if (videoChannelInfoToUpdate.bulkVideosSupportUpdate === true && oldSupportField !== videoChannelInfoToUpdate.support) { | ||
179 | doBulkVideoUpdate = true | ||
180 | await VideoModel.bulkUpdateSupportField(videoChannelInstance, t) | ||
181 | } | ||
182 | } | ||
173 | 183 | ||
174 | const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) | 184 | const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) |
175 | await sendUpdateActor(videoChannelInstanceUpdated, t) | 185 | await sendUpdateActor(videoChannelInstanceUpdated, t) |
@@ -179,6 +189,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
179 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), | 189 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), |
180 | oldVideoChannelAuditKeys | 190 | oldVideoChannelAuditKeys |
181 | ) | 191 | ) |
192 | |||
182 | logger.info('Video channel %s updated.', videoChannelInstance.Actor.url) | 193 | logger.info('Video channel %s updated.', videoChannelInstance.Actor.url) |
183 | }) | 194 | }) |
184 | } catch (err) { | 195 | } catch (err) { |
@@ -192,7 +203,12 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
192 | throw err | 203 | throw err |
193 | } | 204 | } |
194 | 205 | ||
195 | return res.type('json').status(204).end() | 206 | res.type('json').status(204).end() |
207 | |||
208 | // Don't process in a transaction, and after the response because it could be long | ||
209 | if (doBulkVideoUpdate) { | ||
210 | await federateAllVideosOfChannel(videoChannelInstance) | ||
211 | } | ||
196 | } | 212 | } |
197 | 213 | ||
198 | async function removeVideoChannel (req: express.Request, res: express.Response) { | 214 | async function removeVideoChannel (req: express.Request, res: express.Response) { |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 3b6eb45c4..daf846513 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -87,6 +87,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act | |||
87 | commentObject.inReplyTo, | 87 | commentObject.inReplyTo, |
88 | { err } | 88 | { err } |
89 | ) | 89 | ) |
90 | return | ||
90 | } | 91 | } |
91 | 92 | ||
92 | const { comment, created } = await addVideoComment(video, commentObject.id) | 93 | const { comment, created } = await addVideoComment(video, commentObject.id) |
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index 0fe95ca09..ee0482c36 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts | |||
@@ -3,7 +3,8 @@ import * as uuidv4 from 'uuid/v4' | |||
3 | import { VideoChannelCreate } from '../../shared/models' | 3 | import { VideoChannelCreate } from '../../shared/models' |
4 | import { AccountModel } from '../models/account/account' | 4 | import { AccountModel } from '../models/account/account' |
5 | import { VideoChannelModel } from '../models/video/video-channel' | 5 | import { VideoChannelModel } from '../models/video/video-channel' |
6 | import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub' | 6 | import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub' |
7 | import { VideoModel } from '../models/video/video' | ||
7 | 8 | ||
8 | async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { | 9 | async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { |
9 | const uuid = uuidv4() | 10 | const uuid = uuidv4() |
@@ -33,8 +34,19 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account | |||
33 | return videoChannelCreated | 34 | return videoChannelCreated |
34 | } | 35 | } |
35 | 36 | ||
37 | async function federateAllVideosOfChannel (videoChannel: VideoChannelModel) { | ||
38 | const videoIds = await VideoModel.getAllIdsFromChannel(videoChannel) | ||
39 | |||
40 | for (const videoId of videoIds) { | ||
41 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) | ||
42 | |||
43 | await federateVideoIfNeeded(video, false) | ||
44 | } | ||
45 | } | ||
46 | |||
36 | // --------------------------------------------------------------------------- | 47 | // --------------------------------------------------------------------------- |
37 | 48 | ||
38 | export { | 49 | export { |
39 | createVideoChannel | 50 | createVideoChannel, |
51 | federateAllVideosOfChannel | ||
40 | } | 52 | } |
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts index 4b26f0bc4..f5a59cacb 100644 --- a/server/middlewares/validators/videos/video-channels.ts +++ b/server/middlewares/validators/videos/video-channels.ts | |||
@@ -14,6 +14,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel' | |||
14 | import { areValidationErrors } from '../utils' | 14 | import { areValidationErrors } from '../utils' |
15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' | 15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' |
16 | import { ActorModel } from '../../../models/activitypub/actor' | 16 | import { ActorModel } from '../../../models/activitypub/actor' |
17 | import { isBooleanValid } from '../../../helpers/custom-validators/misc' | ||
17 | 18 | ||
18 | const videoChannelsAddValidator = [ | 19 | const videoChannelsAddValidator = [ |
19 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), | 20 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), |
@@ -40,9 +41,18 @@ const videoChannelsAddValidator = [ | |||
40 | 41 | ||
41 | const videoChannelsUpdateValidator = [ | 42 | const videoChannelsUpdateValidator = [ |
42 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), | 43 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), |
43 | body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), | 44 | body('displayName') |
44 | body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), | 45 | .optional() |
45 | body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), | 46 | .custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), |
47 | body('description') | ||
48 | .optional() | ||
49 | .custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), | ||
50 | body('support') | ||
51 | .optional() | ||
52 | .custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), | ||
53 | body('bulkVideosSupportUpdate') | ||
54 | .optional() | ||
55 | .custom(isBooleanValid).withMessage('Should have a valid bulkVideosSupportUpdate boolean field'), | ||
46 | 56 | ||
47 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 57 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
48 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) | 58 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index c0a7892a4..eccf0a4fa 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1515,6 +1515,29 @@ export class VideoModel extends Model<VideoModel> { | |||
1515 | .then(results => results.length === 1) | 1515 | .then(results => results.length === 1) |
1516 | } | 1516 | } |
1517 | 1517 | ||
1518 | static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) { | ||
1519 | const options = { | ||
1520 | where: { | ||
1521 | channelId: videoChannel.id | ||
1522 | }, | ||
1523 | transaction: t | ||
1524 | } | ||
1525 | |||
1526 | return VideoModel.update({ support: videoChannel.support }, options) | ||
1527 | } | ||
1528 | |||
1529 | static getAllIdsFromChannel (videoChannel: VideoChannelModel) { | ||
1530 | const query = { | ||
1531 | attributes: [ 'id' ], | ||
1532 | where: { | ||
1533 | channelId: videoChannel.id | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | return VideoModel.findAll(query) | ||
1538 | .then(videos => videos.map(v => v.id)) | ||
1539 | } | ||
1540 | |||
1518 | // threshold corresponds to how many video the field should have to be returned | 1541 | // threshold corresponds to how many video the field should have to be returned |
1519 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { | 1542 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { |
1520 | const serverActor = await getServerActor() | 1543 | const serverActor = await getServerActor() |
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index ff04f6b03..de88298d1 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts | |||
@@ -24,6 +24,7 @@ import { | |||
24 | checkBadStartPagination | 24 | checkBadStartPagination |
25 | } from '../../../../shared/extra-utils/requests/check-api-params' | 25 | } from '../../../../shared/extra-utils/requests/check-api-params' |
26 | import { join } from 'path' | 26 | import { join } from 'path' |
27 | import { VideoChannelUpdate } from '../../../../shared/models/videos' | ||
27 | 28 | ||
28 | const expect = chai.expect | 29 | const expect = chai.expect |
29 | 30 | ||
@@ -169,9 +170,11 @@ describe('Test video channels API validator', function () { | |||
169 | }) | 170 | }) |
170 | 171 | ||
171 | describe('When updating a video channel', function () { | 172 | describe('When updating a video channel', function () { |
172 | const baseCorrectParams = { | 173 | const baseCorrectParams: VideoChannelUpdate = { |
173 | displayName: 'hello', | 174 | displayName: 'hello', |
174 | description: 'super description' | 175 | description: 'super description', |
176 | support: 'toto', | ||
177 | bulkVideosSupportUpdate: false | ||
175 | } | 178 | } |
176 | let path: string | 179 | let path: string |
177 | 180 | ||
@@ -214,6 +217,11 @@ describe('Test video channels API validator', function () { | |||
214 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | 217 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) |
215 | }) | 218 | }) |
216 | 219 | ||
220 | it('Should fail with a bad bulkVideosSupportUpdate field', async function () { | ||
221 | const fields = immutableAssign(baseCorrectParams, { bulkVideosSupportUpdate: 'super' }) | ||
222 | await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
223 | }) | ||
224 | |||
217 | it('Should succeed with the correct parameters', async function () { | 225 | it('Should succeed with the correct parameters', async function () { |
218 | await makePutBodyRequest({ | 226 | await makePutBodyRequest({ |
219 | url: server.url, | 227 | url: server.url, |
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index 2d298dd3f..4f600cae8 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { User, Video, VideoChannel } from '../../../../shared/index' | 5 | import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, getVideo, |
11 | getVideoChannelVideos, | 11 | getVideoChannelVideos, |
12 | testImage, | 12 | testImage, |
13 | updateVideo, | 13 | updateVideo, |
@@ -79,7 +79,8 @@ describe('Test video channels', function () { | |||
79 | 79 | ||
80 | // The channel is 1 is propagated to servers 2 | 80 | // The channel is 1 is propagated to servers 2 |
81 | { | 81 | { |
82 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name', channelId: secondVideoChannelId }) | 82 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } |
83 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg) | ||
83 | videoUUID = res.body.video.uuid | 84 | videoUUID = res.body.video.uuid |
84 | } | 85 | } |
85 | 86 | ||
@@ -201,12 +202,12 @@ describe('Test video channels', function () { | |||
201 | }) | 202 | }) |
202 | 203 | ||
203 | it('Should update video channel', async function () { | 204 | it('Should update video channel', async function () { |
204 | this.timeout(5000) | 205 | this.timeout(15000) |
205 | 206 | ||
206 | const videoChannelAttributes = { | 207 | const videoChannelAttributes = { |
207 | displayName: 'video channel updated', | 208 | displayName: 'video channel updated', |
208 | description: 'video channel description updated', | 209 | description: 'video channel description updated', |
209 | support: 'video channel support text updated' | 210 | support: 'support updated' |
210 | } | 211 | } |
211 | 212 | ||
212 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) | 213 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) |
@@ -224,7 +225,36 @@ describe('Test video channels', function () { | |||
224 | expect(res.body.data[0].name).to.equal('second_video_channel') | 225 | expect(res.body.data[0].name).to.equal('second_video_channel') |
225 | expect(res.body.data[0].displayName).to.equal('video channel updated') | 226 | expect(res.body.data[0].displayName).to.equal('video channel updated') |
226 | expect(res.body.data[0].description).to.equal('video channel description updated') | 227 | expect(res.body.data[0].description).to.equal('video channel description updated') |
227 | expect(res.body.data[0].support).to.equal('video channel support text updated') | 228 | expect(res.body.data[0].support).to.equal('support updated') |
229 | } | ||
230 | }) | ||
231 | |||
232 | it('Should not have updated the video support field', async function () { | ||
233 | for (const server of servers) { | ||
234 | const res = await getVideo(server.url, videoUUID) | ||
235 | const video: VideoDetails = res.body | ||
236 | |||
237 | expect(video.support).to.equal('video support field') | ||
238 | } | ||
239 | }) | ||
240 | |||
241 | it('Should update the channel support field and update videos too', async function () { | ||
242 | this.timeout(35000) | ||
243 | |||
244 | const videoChannelAttributes = { | ||
245 | support: 'video channel support text updated', | ||
246 | bulkVideosSupportUpdate: true | ||
247 | } | ||
248 | |||
249 | await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) | ||
250 | |||
251 | await waitJobs(servers) | ||
252 | |||
253 | for (const server of servers) { | ||
254 | const res = await getVideo(server.url, videoUUID) | ||
255 | const video: VideoDetails = res.body | ||
256 | |||
257 | expect(video.support).to.equal(videoChannelAttributes.support) | ||
228 | } | 258 | } |
229 | }) | 259 | }) |
230 | 260 | ||