diff options
-rw-r--r-- | client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/users/index.ts | 2 | ||||
-rw-r--r-- | server/controllers/api/videos/ownership.ts | 33 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/undo.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-undo.ts | 10 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-announce.ts | 5 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-update.ts | 10 | ||||
-rw-r--r-- | server/lib/activitypub/share.ts | 2 | ||||
-rw-r--r-- | server/models/account/user.ts | 32 | ||||
-rw-r--r-- | server/models/video/video-change-ownership.ts | 12 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 16 | ||||
-rw-r--r-- | server/tests/api/videos/index.ts | 1 | ||||
-rw-r--r-- | server/tests/api/videos/video-change-ownership.ts | 85 |
13 files changed, 138 insertions, 78 deletions
diff --git a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts index 0aa4c32ee..7437b939a 100644 --- a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts +++ b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts | |||
@@ -53,7 +53,7 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni | |||
53 | const query = event.query | 53 | const query = event.query |
54 | this.userService.autocomplete(query) | 54 | this.userService.autocomplete(query) |
55 | .subscribe( | 55 | .subscribe( |
56 | (usernames) => { | 56 | usernames => { |
57 | this.usernamePropositions = usernames | 57 | this.usernamePropositions = usernames |
58 | }, | 58 | }, |
59 | 59 | ||
@@ -67,7 +67,7 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni | |||
67 | this.videoOwnershipService | 67 | this.videoOwnershipService |
68 | .changeOwnership(this.video.id, username) | 68 | .changeOwnership(this.video.id, username) |
69 | .subscribe( | 69 | .subscribe( |
70 | () => this.notificationsService.success(this.i18n('Success'), this.i18n('Ownership changed.')), | 70 | () => this.notificationsService.success(this.i18n('Success'), this.i18n('Ownership change request sent.')), |
71 | 71 | ||
72 | err => this.notificationsService.error(this.i18n('Error'), err.message) | 72 | err => this.notificationsService.error(this.i18n('Error'), err.message) |
73 | ) | 73 | ) |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index faba7e208..07edf3727 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -229,7 +229,7 @@ function getUser (req: express.Request, res: express.Response, next: express.Nex | |||
229 | } | 229 | } |
230 | 230 | ||
231 | async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) { | 231 | async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) { |
232 | const resultList = await UserModel.autocomplete(req.query.search as string) | 232 | const resultList = await UserModel.autoComplete(req.query.search as string) |
233 | 233 | ||
234 | return res.json(resultList) | 234 | return res.json(resultList) |
235 | } | 235 | } |
diff --git a/server/controllers/api/videos/ownership.ts b/server/controllers/api/videos/ownership.ts index fc42f5fff..d26ed6cfc 100644 --- a/server/controllers/api/videos/ownership.ts +++ b/server/controllers/api/videos/ownership.ts | |||
@@ -14,9 +14,11 @@ import { | |||
14 | import { AccountModel } from '../../../models/account/account' | 14 | import { AccountModel } from '../../../models/account/account' |
15 | import { VideoModel } from '../../../models/video/video' | 15 | import { VideoModel } from '../../../models/video/video' |
16 | import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ownership' | 16 | import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ownership' |
17 | import { VideoChangeOwnershipStatus } from '../../../../shared/models/videos' | 17 | import { VideoChangeOwnershipStatus, VideoPrivacy, VideoState } from '../../../../shared/models/videos' |
18 | import { VideoChannelModel } from '../../../models/video/video-channel' | 18 | import { VideoChannelModel } from '../../../models/video/video-channel' |
19 | import { getFormattedObjects } from '../../../helpers/utils' | 19 | import { getFormattedObjects } from '../../../helpers/utils' |
20 | import { changeVideoChannelShare } from '../../../lib/activitypub' | ||
21 | import { sendUpdateVideo } from '../../../lib/activitypub/send' | ||
20 | 22 | ||
21 | const ownershipVideoRouter = express.Router() | 23 | const ownershipVideoRouter = express.Router() |
22 | 24 | ||
@@ -59,8 +61,8 @@ async function giveVideoOwnership (req: express.Request, res: express.Response) | |||
59 | const initiatorAccount = res.locals.oauth.token.User.Account as AccountModel | 61 | const initiatorAccount = res.locals.oauth.token.User.Account as AccountModel |
60 | const nextOwner = res.locals.nextOwner as AccountModel | 62 | const nextOwner = res.locals.nextOwner as AccountModel |
61 | 63 | ||
62 | await sequelizeTypescript.transaction(async t => { | 64 | await sequelizeTypescript.transaction(t => { |
63 | await VideoChangeOwnershipModel.findOrCreate({ | 65 | return VideoChangeOwnershipModel.findOrCreate({ |
64 | where: { | 66 | where: { |
65 | initiatorAccountId: initiatorAccount.id, | 67 | initiatorAccountId: initiatorAccount.id, |
66 | nextOwnerAccountId: nextOwner.id, | 68 | nextOwnerAccountId: nextOwner.id, |
@@ -72,11 +74,14 @@ async function giveVideoOwnership (req: express.Request, res: express.Response) | |||
72 | nextOwnerAccountId: nextOwner.id, | 74 | nextOwnerAccountId: nextOwner.id, |
73 | videoId: videoInstance.id, | 75 | videoId: videoInstance.id, |
74 | status: VideoChangeOwnershipStatus.WAITING | 76 | status: VideoChangeOwnershipStatus.WAITING |
75 | } | 77 | }, |
78 | transaction: t | ||
76 | }) | 79 | }) |
77 | logger.info('Ownership change for video %s created.', videoInstance.name) | 80 | |
78 | return res.type('json').status(204).end() | ||
79 | }) | 81 | }) |
82 | |||
83 | logger.info('Ownership change for video %s created.', videoInstance.name) | ||
84 | return res.type('json').status(204).end() | ||
80 | } | 85 | } |
81 | 86 | ||
82 | async function listVideoOwnership (req: express.Request, res: express.Response) { | 87 | async function listVideoOwnership (req: express.Request, res: express.Response) { |
@@ -97,11 +102,19 @@ async function acceptOwnership (req: express.Request, res: express.Response) { | |||
97 | const targetVideo = videoChangeOwnership.Video | 102 | const targetVideo = videoChangeOwnership.Video |
98 | const channel = res.locals.videoChannel as VideoChannelModel | 103 | const channel = res.locals.videoChannel as VideoChannelModel |
99 | 104 | ||
105 | const oldVideoChannel = await VideoChannelModel.loadByIdAndPopulateAccount(targetVideo.channelId) | ||
106 | |||
100 | targetVideo.set('channelId', channel.id) | 107 | targetVideo.set('channelId', channel.id) |
108 | const targetVideoUpdated = await targetVideo.save({ transaction: t }) | ||
109 | targetVideoUpdated.VideoChannel = channel | ||
110 | |||
111 | if (targetVideoUpdated.privacy !== VideoPrivacy.PRIVATE && targetVideoUpdated.state === VideoState.PUBLISHED) { | ||
112 | await changeVideoChannelShare(targetVideoUpdated, oldVideoChannel, t) | ||
113 | await sendUpdateVideo(targetVideoUpdated, t, oldVideoChannel.Account.Actor) | ||
114 | } | ||
101 | 115 | ||
102 | await targetVideo.save() | ||
103 | videoChangeOwnership.set('status', VideoChangeOwnershipStatus.ACCEPTED) | 116 | videoChangeOwnership.set('status', VideoChangeOwnershipStatus.ACCEPTED) |
104 | await videoChangeOwnership.save() | 117 | await videoChangeOwnership.save({ transaction: t }) |
105 | 118 | ||
106 | return res.sendStatus(204) | 119 | return res.sendStatus(204) |
107 | }) | 120 | }) |
@@ -110,8 +123,10 @@ async function acceptOwnership (req: express.Request, res: express.Response) { | |||
110 | async function refuseOwnership (req: express.Request, res: express.Response) { | 123 | async function refuseOwnership (req: express.Request, res: express.Response) { |
111 | return sequelizeTypescript.transaction(async t => { | 124 | return sequelizeTypescript.transaction(async t => { |
112 | const videoChangeOwnership = res.locals.videoChangeOwnership as VideoChangeOwnershipModel | 125 | const videoChangeOwnership = res.locals.videoChangeOwnership as VideoChangeOwnershipModel |
126 | |||
113 | videoChangeOwnership.set('status', VideoChangeOwnershipStatus.REFUSED) | 127 | videoChangeOwnership.set('status', VideoChangeOwnershipStatus.REFUSED) |
114 | await videoChangeOwnership.save() | 128 | await videoChangeOwnership.save({ transaction: t }) |
129 | |||
115 | return res.sendStatus(204) | 130 | return res.sendStatus(204) |
116 | }) | 131 | }) |
117 | } | 132 | } |
diff --git a/server/helpers/custom-validators/activitypub/undo.ts b/server/helpers/custom-validators/activitypub/undo.ts index a2831b0bf..f50f224fa 100644 --- a/server/helpers/custom-validators/activitypub/undo.ts +++ b/server/helpers/custom-validators/activitypub/undo.ts | |||
@@ -1,13 +1,15 @@ | |||
1 | import { isActorFollowActivityValid } from './actor' | 1 | import { isActorFollowActivityValid } from './actor' |
2 | import { isBaseActivityValid } from './misc' | 2 | import { isBaseActivityValid } from './misc' |
3 | import { isDislikeActivityValid, isLikeActivityValid } from './rate' | 3 | import { isDislikeActivityValid, isLikeActivityValid } from './rate' |
4 | import { isAnnounceActivityValid } from './announce' | ||
4 | 5 | ||
5 | function isUndoActivityValid (activity: any) { | 6 | function isUndoActivityValid (activity: any) { |
6 | return isBaseActivityValid(activity, 'Undo') && | 7 | return isBaseActivityValid(activity, 'Undo') && |
7 | ( | 8 | ( |
8 | isActorFollowActivityValid(activity.object) || | 9 | isActorFollowActivityValid(activity.object) || |
9 | isLikeActivityValid(activity.object) || | 10 | isLikeActivityValid(activity.object) || |
10 | isDislikeActivityValid(activity.object) | 11 | isDislikeActivityValid(activity.object) || |
12 | isAnnounceActivityValid(activity.object) | ||
11 | ) | 13 | ) |
12 | } | 14 | } |
13 | 15 | ||
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index eab9e3d61..1c1de8827 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts | |||
@@ -104,17 +104,19 @@ function processUndoFollow (actorUrl: string, followActivity: ActivityFollow) { | |||
104 | 104 | ||
105 | function processUndoAnnounce (actorUrl: string, announceActivity: ActivityAnnounce) { | 105 | function processUndoAnnounce (actorUrl: string, announceActivity: ActivityAnnounce) { |
106 | return sequelizeTypescript.transaction(async t => { | 106 | return sequelizeTypescript.transaction(async t => { |
107 | const byAccount = await AccountModel.loadByUrl(actorUrl, t) | 107 | const byActor = await ActorModel.loadByUrl(actorUrl, t) |
108 | if (!byAccount) throw new Error('Unknown account ' + actorUrl) | 108 | if (!byActor) throw new Error('Unknown actor ' + actorUrl) |
109 | 109 | ||
110 | const share = await VideoShareModel.loadByUrl(announceActivity.id, t) | 110 | const share = await VideoShareModel.loadByUrl(announceActivity.id, t) |
111 | if (!share) throw new Error(`'Unknown video share ${announceActivity.id}.`) | 111 | if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) |
112 | |||
113 | if (share.actorId !== byActor.id) throw new Error(`${share.url} is not shared by ${byActor.url}.`) | ||
112 | 114 | ||
113 | await share.destroy({ transaction: t }) | 115 | await share.destroy({ transaction: t }) |
114 | 116 | ||
115 | if (share.Video.isOwned()) { | 117 | if (share.Video.isOwned()) { |
116 | // Don't resend the activity to the sender | 118 | // Don't resend the activity to the sender |
117 | const exceptions = [ byAccount.Actor ] | 119 | const exceptions = [ byActor ] |
118 | 120 | ||
119 | await forwardVideoRelatedActivity(announceActivity, t, exceptions, share.Video) | 121 | await forwardVideoRelatedActivity(announceActivity, t, exceptions, share.Video) |
120 | } | 122 | } |
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index 1ab05ca3c..352813d73 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -20,7 +20,10 @@ async function sendVideoAnnounce (byActor: ActorModel, videoShare: VideoShareMod | |||
20 | 20 | ||
21 | logger.info('Creating job to send announce %s.', videoShare.url) | 21 | logger.info('Creating job to send announce %s.', videoShare.url) |
22 | 22 | ||
23 | return broadcastToFollowers(data, byActor, [ byActor ], t) | 23 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) |
24 | const followersException = [ byActor ] | ||
25 | |||
26 | return broadcastToFollowers(data, byActor, actorsInvolvedInVideo, t, followersException) | ||
24 | } | 27 | } |
25 | 28 | ||
26 | function announceActivityData (url: string, byActor: ActorModel, object: string, audience?: ActivityAudience): ActivityAnnounce { | 29 | function announceActivityData (url: string, byActor: ActorModel, object: string, audience?: ActivityAudience): ActivityAnnounce { |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 17d4f185c..6f1d80898 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -10,13 +10,19 @@ import { getUpdateActivityPubUrl } from '../url' | |||
10 | import { broadcastToFollowers } from './utils' | 10 | import { broadcastToFollowers } from './utils' |
11 | import { audiencify, getAudience } from '../audience' | 11 | import { audiencify, getAudience } from '../audience' |
12 | import { logger } from '../../../helpers/logger' | 12 | import { logger } from '../../../helpers/logger' |
13 | import { videoFeedsValidator } from '../../../middlewares/validators' | ||
14 | import { VideoCaptionModel } from '../../../models/video/video-caption' | ||
13 | 15 | ||
14 | async function sendUpdateVideo (video: VideoModel, t: Transaction) { | 16 | async function sendUpdateVideo (video: VideoModel, t: Transaction, overrodeByActor?: ActorModel) { |
15 | logger.info('Creating job to update video %s.', video.url) | 17 | logger.info('Creating job to update video %s.', video.url) |
16 | 18 | ||
17 | const byActor = video.VideoChannel.Account.Actor | 19 | const byActor = overrodeByActor ? overrodeByActor : video.VideoChannel.Account.Actor |
18 | 20 | ||
19 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) | 21 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) |
22 | |||
23 | // Needed to build the AP object | ||
24 | if (!video.VideoCaptions) video.VideoCaptions = await video.$get('VideoCaptions') as VideoCaptionModel[] | ||
25 | |||
20 | const videoObject = video.toActivityPubObject() | 26 | const videoObject = video.toActivityPubObject() |
21 | const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC) | 27 | const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC) |
22 | 28 | ||
diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index fe3d73e9b..3ff60a97c 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts | |||
@@ -22,6 +22,8 @@ async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) | |||
22 | } | 22 | } |
23 | 23 | ||
24 | async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { | 24 | async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { |
25 | logger.info('Updating video channel of video %s: %s -> %s.', video.uuid, oldVideoChannel.name, video.VideoChannel.name) | ||
26 | |||
25 | await undoShareByVideoChannel(video, oldVideoChannel, t) | 27 | await undoShareByVideoChannel(video, oldVideoChannel, t) |
26 | 28 | ||
27 | await shareByVideoChannel(video, t) | 29 | await shareByVideoChannel(video, t) |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 4b13e47a0..680b1d52d 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -23,13 +23,13 @@ import { | |||
23 | isUserAutoPlayVideoValid, | 23 | isUserAutoPlayVideoValid, |
24 | isUserBlockedReasonValid, | 24 | isUserBlockedReasonValid, |
25 | isUserBlockedValid, | 25 | isUserBlockedValid, |
26 | isUserNSFWPolicyValid, | ||
27 | isUserEmailVerifiedValid, | 26 | isUserEmailVerifiedValid, |
27 | isUserNSFWPolicyValid, | ||
28 | isUserPasswordValid, | 28 | isUserPasswordValid, |
29 | isUserRoleValid, | 29 | isUserRoleValid, |
30 | isUserUsernameValid, | 30 | isUserUsernameValid, |
31 | isUserVideoQuotaValid, | 31 | isUserVideoQuotaDailyValid, |
32 | isUserVideoQuotaDailyValid | 32 | isUserVideoQuotaValid |
33 | } from '../../helpers/custom-validators/users' | 33 | } from '../../helpers/custom-validators/users' |
34 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' | 34 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' |
35 | import { OAuthTokenModel } from '../oauth/oauth-token' | 35 | import { OAuthTokenModel } from '../oauth/oauth-token' |
@@ -39,7 +39,6 @@ import { AccountModel } from './account' | |||
39 | import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' | 39 | import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' |
40 | import { values } from 'lodash' | 40 | import { values } from 'lodash' |
41 | import { NSFW_POLICY_TYPES } from '../../initializers' | 41 | import { NSFW_POLICY_TYPES } from '../../initializers' |
42 | import { VideoFileModel } from '../video/video-file' | ||
43 | 42 | ||
44 | enum ScopeNames { | 43 | enum ScopeNames { |
45 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' | 44 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' |
@@ -296,6 +295,20 @@ export class UserModel extends Model<UserModel> { | |||
296 | } | 295 | } |
297 | } | 296 | } |
298 | 297 | ||
298 | static autoComplete (search: string) { | ||
299 | const query = { | ||
300 | where: { | ||
301 | username: { | ||
302 | [ Sequelize.Op.like ]: `%${search}%` | ||
303 | } | ||
304 | }, | ||
305 | limit: 10 | ||
306 | } | ||
307 | |||
308 | return UserModel.findAll(query) | ||
309 | .then(u => u.map(u => u.username)) | ||
310 | } | ||
311 | |||
299 | hasRight (right: UserRight) { | 312 | hasRight (right: UserRight) { |
300 | return hasUserRight(this.role, right) | 313 | return hasUserRight(this.role, right) |
301 | } | 314 | } |
@@ -394,15 +407,4 @@ export class UserModel extends Model<UserModel> { | |||
394 | return parseInt(total, 10) | 407 | return parseInt(total, 10) |
395 | }) | 408 | }) |
396 | } | 409 | } |
397 | |||
398 | static autocomplete (search: string) { | ||
399 | return UserModel.findAll({ | ||
400 | where: { | ||
401 | username: { | ||
402 | [Sequelize.Op.like]: `%${search}%` | ||
403 | } | ||
404 | } | ||
405 | }) | ||
406 | .then(u => u.map(u => u.username)) | ||
407 | } | ||
408 | } | 410 | } |
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index c9cff5054..48c07728f 100644 --- a/server/models/video/video-change-ownership.ts +++ b/server/models/video/video-change-ownership.ts | |||
@@ -39,7 +39,9 @@ enum ScopeNames { | |||
39 | { | 39 | { |
40 | model: () => VideoModel, | 40 | model: () => VideoModel, |
41 | required: true, | 41 | required: true, |
42 | include: [{ model: () => VideoFileModel }] | 42 | include: [ |
43 | { model: () => VideoFileModel } | ||
44 | ] | ||
43 | } | 45 | } |
44 | ] | 46 | ] |
45 | } | 47 | } |
@@ -94,15 +96,17 @@ export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> | |||
94 | Video: VideoModel | 96 | Video: VideoModel |
95 | 97 | ||
96 | static listForApi (nextOwnerId: number, start: number, count: number, sort: string) { | 98 | static listForApi (nextOwnerId: number, start: number, count: number, sort: string) { |
97 | return VideoChangeOwnershipModel.scope(ScopeNames.FULL).findAndCountAll({ | 99 | const query = { |
98 | offset: start, | 100 | offset: start, |
99 | limit: count, | 101 | limit: count, |
100 | order: getSort(sort), | 102 | order: getSort(sort), |
101 | where: { | 103 | where: { |
102 | nextOwnerAccountId: nextOwnerId | 104 | nextOwnerAccountId: nextOwnerId |
103 | } | 105 | } |
104 | }) | 106 | } |
105 | .then(({ rows, count }) => ({ total: count, data: rows })) | 107 | |
108 | return VideoChangeOwnershipModel.scope(ScopeNames.FULL).findAndCountAll(query) | ||
109 | .then(({ rows, count }) => ({ total: count, data: rows })) | ||
106 | } | 110 | } |
107 | 111 | ||
108 | static load (id: number) { | 112 | static load (id: number) { |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 475530daf..f4586917e 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -296,6 +296,12 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
296 | }) | 296 | }) |
297 | } | 297 | } |
298 | 298 | ||
299 | static loadByIdAndPopulateAccount (id: number) { | ||
300 | return VideoChannelModel.unscoped() | ||
301 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | ||
302 | .findById(id) | ||
303 | } | ||
304 | |||
299 | static loadByIdAndAccount (id: number, accountId: number) { | 305 | static loadByIdAndAccount (id: number, accountId: number) { |
300 | const query = { | 306 | const query = { |
301 | where: { | 307 | where: { |
@@ -304,13 +310,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
304 | } | 310 | } |
305 | } | 311 | } |
306 | 312 | ||
307 | return VideoChannelModel | 313 | return VideoChannelModel.unscoped() |
308 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 314 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
309 | .findOne(query) | 315 | .findOne(query) |
310 | } | 316 | } |
311 | 317 | ||
312 | static loadAndPopulateAccount (id: number) { | 318 | static loadAndPopulateAccount (id: number) { |
313 | return VideoChannelModel | 319 | return VideoChannelModel.unscoped() |
314 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 320 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
315 | .findById(id) | 321 | .findById(id) |
316 | } | 322 | } |
@@ -365,7 +371,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
365 | ] | 371 | ] |
366 | } | 372 | } |
367 | 373 | ||
368 | return VideoChannelModel | 374 | return VideoChannelModel.unscoped() |
369 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 375 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
370 | .findOne(query) | 376 | .findOne(query) |
371 | } | 377 | } |
@@ -390,7 +396,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
390 | ] | 396 | ] |
391 | } | 397 | } |
392 | 398 | ||
393 | return VideoChannelModel | 399 | return VideoChannelModel.unscoped() |
394 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 400 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
395 | .findOne(query) | 401 | .findOne(query) |
396 | } | 402 | } |
@@ -402,7 +408,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
402 | ] | 408 | ] |
403 | } | 409 | } |
404 | 410 | ||
405 | return VideoChannelModel | 411 | return VideoChannelModel.unscoped() |
406 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]) | 412 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]) |
407 | .findById(id, options) | 413 | .findById(id, options) |
408 | } | 414 | } |
diff --git a/server/tests/api/videos/index.ts b/server/tests/api/videos/index.ts index 8286ff356..a328a49c1 100644 --- a/server/tests/api/videos/index.ts +++ b/server/tests/api/videos/index.ts | |||
@@ -5,6 +5,7 @@ import './video-abuse' | |||
5 | import './video-blacklist' | 5 | import './video-blacklist' |
6 | import './video-blacklist-management' | 6 | import './video-blacklist-management' |
7 | import './video-captions' | 7 | import './video-captions' |
8 | import './vidoe-change-ownership' | ||
8 | import './video-channels' | 9 | import './video-channels' |
9 | import './video-comments' | 10 | import './video-comments' |
10 | import './video-description' | 11 | import './video-description' |
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index 275be40be..1578a471d 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts | |||
@@ -5,7 +5,7 @@ import 'mocha' | |||
5 | import { | 5 | import { |
6 | acceptChangeOwnership, | 6 | acceptChangeOwnership, |
7 | changeVideoOwnership, | 7 | changeVideoOwnership, |
8 | createUser, | 8 | createUser, doubleFollow, flushAndRunMultipleServers, |
9 | flushTests, | 9 | flushTests, |
10 | getMyUserInformation, | 10 | getMyUserInformation, |
11 | getVideoChangeOwnershipList, | 11 | getVideoChangeOwnershipList, |
@@ -16,15 +16,17 @@ import { | |||
16 | ServerInfo, | 16 | ServerInfo, |
17 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
18 | uploadVideo, | 18 | uploadVideo, |
19 | userLogin | 19 | userLogin, |
20 | getVideo | ||
20 | } from '../../utils' | 21 | } from '../../utils' |
21 | import { waitJobs } from '../../utils/server/jobs' | 22 | import { waitJobs } from '../../utils/server/jobs' |
22 | import { User } from '../../../../shared/models/users' | 23 | import { User } from '../../../../shared/models/users' |
24 | import { VideoDetails } from '../../../../shared/models/videos' | ||
23 | 25 | ||
24 | const expect = chai.expect | 26 | const expect = chai.expect |
25 | 27 | ||
26 | describe('Test video change ownership - nominal', function () { | 28 | describe('Test video change ownership - nominal', function () { |
27 | let server: ServerInfo = undefined | 29 | let servers: ServerInfo[] = [] |
28 | const firstUser = { | 30 | const firstUser = { |
29 | username: 'first', | 31 | username: 'first', |
30 | password: 'My great password' | 32 | password: 'My great password' |
@@ -40,43 +42,44 @@ describe('Test video change ownership - nominal', function () { | |||
40 | before(async function () { | 42 | before(async function () { |
41 | this.timeout(50000) | 43 | this.timeout(50000) |
42 | 44 | ||
43 | // Run one server | 45 | servers = await flushAndRunMultipleServers(2) |
44 | await flushTests() | 46 | await setAccessTokensToServers(servers) |
45 | server = await runServer(1) | ||
46 | await setAccessTokensToServers([server]) | ||
47 | 47 | ||
48 | const videoQuota = 42000000 | 48 | const videoQuota = 42000000 |
49 | await createUser(server.url, server.accessToken, firstUser.username, firstUser.password, videoQuota) | 49 | await createUser(servers[0].url, servers[0].accessToken, firstUser.username, firstUser.password, videoQuota) |
50 | await createUser(server.url, server.accessToken, secondUser.username, secondUser.password, videoQuota) | 50 | await createUser(servers[0].url, servers[0].accessToken, secondUser.username, secondUser.password, videoQuota) |
51 | 51 | ||
52 | firstUserAccessToken = await userLogin(server, firstUser) | 52 | firstUserAccessToken = await userLogin(servers[0], firstUser) |
53 | secondUserAccessToken = await userLogin(server, secondUser) | 53 | secondUserAccessToken = await userLogin(servers[0], secondUser) |
54 | 54 | ||
55 | // Upload some videos on the server | 55 | const videoAttributes = { |
56 | const video1Attributes = { | ||
57 | name: 'my super name', | 56 | name: 'my super name', |
58 | description: 'my super description' | 57 | description: 'my super description' |
59 | } | 58 | } |
60 | await uploadVideo(server.url, firstUserAccessToken, video1Attributes) | 59 | await uploadVideo(servers[0].url, firstUserAccessToken, videoAttributes) |
61 | 60 | ||
62 | await waitJobs(server) | 61 | await waitJobs(servers) |
63 | 62 | ||
64 | const res = await getVideosList(server.url) | 63 | const res = await getVideosList(servers[0].url) |
65 | const videos = res.body.data | 64 | const videos = res.body.data |
66 | 65 | ||
67 | expect(videos.length).to.equal(1) | 66 | expect(videos.length).to.equal(1) |
68 | 67 | ||
69 | server.video = videos.find(video => video.name === 'my super name') | 68 | const video = videos.find(video => video.name === 'my super name') |
69 | expect(video.channel.name).to.equal('first_channel') | ||
70 | servers[0].video = video | ||
71 | |||
72 | await doubleFollow(servers[0], servers[1]) | ||
70 | }) | 73 | }) |
71 | 74 | ||
72 | it('Should not have video change ownership', async function () { | 75 | it('Should not have video change ownership', async function () { |
73 | const resFirstUser = await getVideoChangeOwnershipList(server.url, firstUserAccessToken) | 76 | const resFirstUser = await getVideoChangeOwnershipList(servers[0].url, firstUserAccessToken) |
74 | 77 | ||
75 | expect(resFirstUser.body.total).to.equal(0) | 78 | expect(resFirstUser.body.total).to.equal(0) |
76 | expect(resFirstUser.body.data).to.be.an('array') | 79 | expect(resFirstUser.body.data).to.be.an('array') |
77 | expect(resFirstUser.body.data.length).to.equal(0) | 80 | expect(resFirstUser.body.data.length).to.equal(0) |
78 | 81 | ||
79 | const resSecondUser = await getVideoChangeOwnershipList(server.url, secondUserAccessToken) | 82 | const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken) |
80 | 83 | ||
81 | expect(resSecondUser.body.total).to.equal(0) | 84 | expect(resSecondUser.body.total).to.equal(0) |
82 | expect(resSecondUser.body.data).to.be.an('array') | 85 | expect(resSecondUser.body.data).to.be.an('array') |
@@ -86,17 +89,17 @@ describe('Test video change ownership - nominal', function () { | |||
86 | it('Should send a request to change ownership of a video', async function () { | 89 | it('Should send a request to change ownership of a video', async function () { |
87 | this.timeout(15000) | 90 | this.timeout(15000) |
88 | 91 | ||
89 | await changeVideoOwnership(server.url, firstUserAccessToken, server.video.id, secondUser.username) | 92 | await changeVideoOwnership(servers[0].url, firstUserAccessToken, servers[0].video.id, secondUser.username) |
90 | }) | 93 | }) |
91 | 94 | ||
92 | it('Should only return a request to change ownership for the second user', async function () { | 95 | it('Should only return a request to change ownership for the second user', async function () { |
93 | const resFirstUser = await getVideoChangeOwnershipList(server.url, firstUserAccessToken) | 96 | const resFirstUser = await getVideoChangeOwnershipList(servers[0].url, firstUserAccessToken) |
94 | 97 | ||
95 | expect(resFirstUser.body.total).to.equal(0) | 98 | expect(resFirstUser.body.total).to.equal(0) |
96 | expect(resFirstUser.body.data).to.be.an('array') | 99 | expect(resFirstUser.body.data).to.be.an('array') |
97 | expect(resFirstUser.body.data.length).to.equal(0) | 100 | expect(resFirstUser.body.data.length).to.equal(0) |
98 | 101 | ||
99 | const resSecondUser = await getVideoChangeOwnershipList(server.url, secondUserAccessToken) | 102 | const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken) |
100 | 103 | ||
101 | expect(resSecondUser.body.total).to.equal(1) | 104 | expect(resSecondUser.body.total).to.equal(1) |
102 | expect(resSecondUser.body.data).to.be.an('array') | 105 | expect(resSecondUser.body.data).to.be.an('array') |
@@ -108,13 +111,13 @@ describe('Test video change ownership - nominal', function () { | |||
108 | it('Should accept the same change ownership request without crashing', async function () { | 111 | it('Should accept the same change ownership request without crashing', async function () { |
109 | this.timeout(10000) | 112 | this.timeout(10000) |
110 | 113 | ||
111 | await changeVideoOwnership(server.url, firstUserAccessToken, server.video.id, secondUser.username) | 114 | await changeVideoOwnership(servers[0].url, firstUserAccessToken, servers[0].video.id, secondUser.username) |
112 | }) | 115 | }) |
113 | 116 | ||
114 | it('Should not create multiple change ownership requests while one is waiting', async function () { | 117 | it('Should not create multiple change ownership requests while one is waiting', async function () { |
115 | this.timeout(10000) | 118 | this.timeout(10000) |
116 | 119 | ||
117 | const resSecondUser = await getVideoChangeOwnershipList(server.url, secondUserAccessToken) | 120 | const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken) |
118 | 121 | ||
119 | expect(resSecondUser.body.total).to.equal(1) | 122 | expect(resSecondUser.body.total).to.equal(1) |
120 | expect(resSecondUser.body.data).to.be.an('array') | 123 | expect(resSecondUser.body.data).to.be.an('array') |
@@ -124,29 +127,29 @@ describe('Test video change ownership - nominal', function () { | |||
124 | it('Should not be possible to refuse the change of ownership from first user', async function () { | 127 | it('Should not be possible to refuse the change of ownership from first user', async function () { |
125 | this.timeout(10000) | 128 | this.timeout(10000) |
126 | 129 | ||
127 | await refuseChangeOwnership(server.url, firstUserAccessToken, lastRequestChangeOwnershipId, 403) | 130 | await refuseChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, 403) |
128 | }) | 131 | }) |
129 | 132 | ||
130 | it('Should be possible to refuse the change of ownership from second user', async function () { | 133 | it('Should be possible to refuse the change of ownership from second user', async function () { |
131 | this.timeout(10000) | 134 | this.timeout(10000) |
132 | 135 | ||
133 | await refuseChangeOwnership(server.url, secondUserAccessToken, lastRequestChangeOwnershipId) | 136 | await refuseChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId) |
134 | }) | 137 | }) |
135 | 138 | ||
136 | it('Should send a new request to change ownership of a video', async function () { | 139 | it('Should send a new request to change ownership of a video', async function () { |
137 | this.timeout(15000) | 140 | this.timeout(15000) |
138 | 141 | ||
139 | await changeVideoOwnership(server.url, firstUserAccessToken, server.video.id, secondUser.username) | 142 | await changeVideoOwnership(servers[0].url, firstUserAccessToken, servers[0].video.id, secondUser.username) |
140 | }) | 143 | }) |
141 | 144 | ||
142 | it('Should return two requests to change ownership for the second user', async function () { | 145 | it('Should return two requests to change ownership for the second user', async function () { |
143 | const resFirstUser = await getVideoChangeOwnershipList(server.url, firstUserAccessToken) | 146 | const resFirstUser = await getVideoChangeOwnershipList(servers[0].url, firstUserAccessToken) |
144 | 147 | ||
145 | expect(resFirstUser.body.total).to.equal(0) | 148 | expect(resFirstUser.body.total).to.equal(0) |
146 | expect(resFirstUser.body.data).to.be.an('array') | 149 | expect(resFirstUser.body.data).to.be.an('array') |
147 | expect(resFirstUser.body.data.length).to.equal(0) | 150 | expect(resFirstUser.body.data.length).to.equal(0) |
148 | 151 | ||
149 | const resSecondUser = await getVideoChangeOwnershipList(server.url, secondUserAccessToken) | 152 | const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken) |
150 | 153 | ||
151 | expect(resSecondUser.body.total).to.equal(2) | 154 | expect(resSecondUser.body.total).to.equal(2) |
152 | expect(resSecondUser.body.data).to.be.an('array') | 155 | expect(resSecondUser.body.data).to.be.an('array') |
@@ -158,23 +161,37 @@ describe('Test video change ownership - nominal', function () { | |||
158 | it('Should not be possible to accept the change of ownership from first user', async function () { | 161 | it('Should not be possible to accept the change of ownership from first user', async function () { |
159 | this.timeout(10000) | 162 | this.timeout(10000) |
160 | 163 | ||
161 | const secondUserInformationResponse = await getMyUserInformation(server.url, secondUserAccessToken) | 164 | const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken) |
162 | const secondUserInformation: User = secondUserInformationResponse.body | 165 | const secondUserInformation: User = secondUserInformationResponse.body |
163 | const channelId = secondUserInformation.videoChannels[0].id | 166 | const channelId = secondUserInformation.videoChannels[0].id |
164 | await acceptChangeOwnership(server.url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, 403) | 167 | await acceptChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, 403) |
165 | }) | 168 | }) |
166 | 169 | ||
167 | it('Should be possible to accept the change of ownership from second user', async function () { | 170 | it('Should be possible to accept the change of ownership from second user', async function () { |
168 | this.timeout(10000) | 171 | this.timeout(10000) |
169 | 172 | ||
170 | const secondUserInformationResponse = await getMyUserInformation(server.url, secondUserAccessToken) | 173 | const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken) |
171 | const secondUserInformation: User = secondUserInformationResponse.body | 174 | const secondUserInformation: User = secondUserInformationResponse.body |
172 | const channelId = secondUserInformation.videoChannels[0].id | 175 | const channelId = secondUserInformation.videoChannels[0].id |
173 | await acceptChangeOwnership(server.url, secondUserAccessToken, lastRequestChangeOwnershipId, channelId) | 176 | await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, channelId) |
177 | |||
178 | await waitJobs(servers) | ||
179 | }) | ||
180 | |||
181 | it('Should have video channel updated', async function () { | ||
182 | for (const server of servers) { | ||
183 | const res = await getVideo(server.url, servers[0].video.uuid) | ||
184 | |||
185 | const video: VideoDetails = res.body | ||
186 | |||
187 | expect(video.name).to.equal('my super name') | ||
188 | expect(video.channel.displayName).to.equal('Main second channel') | ||
189 | expect(video.channel.name).to.equal('second_channel') | ||
190 | } | ||
174 | }) | 191 | }) |
175 | 192 | ||
176 | after(async function () { | 193 | after(async function () { |
177 | killallServers([server]) | 194 | killallServers(servers) |
178 | }) | 195 | }) |
179 | }) | 196 | }) |
180 | 197 | ||