aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xscripts/update-host.ts20
-rw-r--r--server/controllers/activitypub/client.ts56
-rw-r--r--server/controllers/api/server/follows.ts2
-rw-r--r--server/controllers/api/video-playlist.ts46
-rw-r--r--server/controllers/api/videos/import.ts4
-rw-r--r--server/controllers/api/videos/index.ts4
-rw-r--r--server/controllers/api/videos/live.ts4
-rw-r--r--server/controllers/api/videos/rate.ts6
-rw-r--r--server/initializers/migrations/0100-activitypub.ts6
-rw-r--r--server/lib/activitypub/process/process-dislike.ts16
-rw-r--r--server/lib/activitypub/process/process-follow.ts16
-rw-r--r--server/lib/activitypub/process/process-like.ts13
-rw-r--r--server/lib/activitypub/send/send-accept.ts11
-rw-r--r--server/lib/activitypub/send/send-dislike.ts4
-rw-r--r--server/lib/activitypub/send/send-flag.ts4
-rw-r--r--server/lib/activitypub/send/send-follow.ts8
-rw-r--r--server/lib/activitypub/send/send-like.ts4
-rw-r--r--server/lib/activitypub/send/send-reject.ts11
-rw-r--r--server/lib/activitypub/send/send-undo.ts30
-rw-r--r--server/lib/activitypub/send/send-view.ts10
-rw-r--r--server/lib/activitypub/share.ts6
-rw-r--r--server/lib/activitypub/url.ts93
-rw-r--r--server/lib/activitypub/video-rates.ts10
-rw-r--r--server/lib/job-queue/handlers/activitypub-follow.ts2
-rw-r--r--server/lib/schedulers/videos-redundancy-scheduler.ts37
-rw-r--r--server/lib/user.ts4
-rw-r--r--server/lib/video-channel.ts8
-rw-r--r--server/lib/video-comment.ts6
-rw-r--r--server/lib/video-playlist.ts6
-rw-r--r--server/middlewares/validators/videos/video-rates.ts1
-rw-r--r--server/models/account/account-video-rate.ts3
-rw-r--r--server/models/activitypub/actor-follow.ts36
-rw-r--r--server/models/video/video-format-utils.ts16
-rw-r--r--server/tests/api/server/follows-moderation.ts8
34 files changed, 278 insertions, 233 deletions
diff --git a/scripts/update-host.ts b/scripts/update-host.ts
index d2fb19c76..b030b21c3 100755
--- a/scripts/update-host.ts
+++ b/scripts/update-host.ts
@@ -6,11 +6,11 @@ import { ActorFollowModel } from '../server/models/activitypub/actor-follow'
6import { VideoModel } from '../server/models/video/video' 6import { VideoModel } from '../server/models/video/video'
7import { ActorModel } from '../server/models/activitypub/actor' 7import { ActorModel } from '../server/models/activitypub/actor'
8import { 8import {
9 getAccountActivityPubUrl, 9 getLocalAccountActivityPubUrl,
10 getVideoActivityPubUrl, 10 getLocalVideoActivityPubUrl,
11 getVideoAnnounceActivityPubUrl, 11 getLocalVideoAnnounceActivityPubUrl,
12 getVideoChannelActivityPubUrl, 12 getLocalVideoChannelActivityPubUrl,
13 getVideoCommentActivityPubUrl 13 getLocalVideoCommentActivityPubUrl
14} from '../server/lib/activitypub/url' 14} from '../server/lib/activitypub/url'
15import { VideoShareModel } from '../server/models/video/video-share' 15import { VideoShareModel } from '../server/models/video/video-share'
16import { VideoCommentModel } from '../server/models/video/video-comment' 16import { VideoCommentModel } from '../server/models/video/video-comment'
@@ -62,8 +62,8 @@ async function run () {
62 console.log('Updating actor ' + actor.url) 62 console.log('Updating actor ' + actor.url)
63 63
64 const newUrl = actor.Account 64 const newUrl = actor.Account
65 ? getAccountActivityPubUrl(actor.preferredUsername) 65 ? getLocalAccountActivityPubUrl(actor.preferredUsername)
66 : getVideoChannelActivityPubUrl(actor.preferredUsername) 66 : getLocalVideoChannelActivityPubUrl(actor.preferredUsername)
67 67
68 actor.url = newUrl 68 actor.url = newUrl
69 actor.inboxUrl = newUrl + '/inbox' 69 actor.inboxUrl = newUrl + '/inbox'
@@ -85,7 +85,7 @@ async function run () {
85 85
86 console.log('Updating video share ' + videoShare.url) 86 console.log('Updating video share ' + videoShare.url)
87 87
88 videoShare.url = getVideoAnnounceActivityPubUrl(videoShare.Actor, videoShare.Video) 88 videoShare.url = getLocalVideoAnnounceActivityPubUrl(videoShare.Actor, videoShare.Video)
89 await videoShare.save() 89 await videoShare.save()
90 } 90 }
91 91
@@ -110,7 +110,7 @@ async function run () {
110 110
111 console.log('Updating comment ' + comment.url) 111 console.log('Updating comment ' + comment.url)
112 112
113 comment.url = getVideoCommentActivityPubUrl(comment.Video, comment) 113 comment.url = getLocalVideoCommentActivityPubUrl(comment.Video, comment)
114 await comment.save() 114 await comment.save()
115 } 115 }
116 116
@@ -120,7 +120,7 @@ async function run () {
120 for (const video of videos) { 120 for (const video of videos) {
121 console.log('Updating video ' + video.uuid) 121 console.log('Updating video ' + video.uuid)
122 122
123 video.url = getVideoActivityPubUrl(video) 123 video.url = getLocalVideoActivityPubUrl(video)
124 await video.save() 124 await video.save()
125 125
126 for (const file of video.VideoFiles) { 126 for (const file of video.VideoFiles) {
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index d85d0aa5f..71a5b6232 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -1,8 +1,7 @@
1import * as cors from 'cors' 1import * as cors from 'cors'
2import * as express from 'express' 2import * as express from 'express'
3import { getRateUrl } from '@server/lib/activitypub/video-rates'
4import { getServerActor } from '@server/models/application/application' 3import { getServerActor } from '@server/models/application/application'
5import { MAccountId, MActorId, MChannelId, MVideoId } from '@server/types/models' 4import { MAccountId, MActorId, MChannelId, MVideoId, MVideoUrl } from '@server/types/models'
6import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' 5import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos'
7import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' 6import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
8import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' 7import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub'
@@ -12,10 +11,10 @@ import { buildAnnounceWithVideoAudience, buildLikeActivity } from '../../lib/act
12import { buildCreateActivity } from '../../lib/activitypub/send/send-create' 11import { buildCreateActivity } from '../../lib/activitypub/send/send-create'
13import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike' 12import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike'
14import { 13import {
15 getVideoCommentsActivityPubUrl, 14 getLocalVideoCommentsActivityPubUrl,
16 getVideoDislikesActivityPubUrl, 15 getLocalVideoDislikesActivityPubUrl,
17 getVideoLikesActivityPubUrl, 16 getLocalVideoLikesActivityPubUrl,
18 getVideoSharesActivityPubUrl 17 getLocalVideoSharesActivityPubUrl
19} from '../../lib/activitypub/url' 18} from '../../lib/activitypub/url'
20import { 19import {
21 asyncMiddleware, 20 asyncMiddleware,
@@ -212,10 +211,9 @@ function getAccountVideoRateFactory (rateType: VideoRateType) {
212 const accountVideoRate = res.locals.accountVideoRate 211 const accountVideoRate = res.locals.accountVideoRate
213 212
214 const byActor = accountVideoRate.Account.Actor 213 const byActor = accountVideoRate.Account.Actor
215 const url = getRateUrl(rateType, byActor, accountVideoRate.Video)
216 const APObject = rateType === 'like' 214 const APObject = rateType === 'like'
217 ? buildLikeActivity(url, byActor, accountVideoRate.Video) 215 ? buildLikeActivity(accountVideoRate.url, byActor, accountVideoRate.Video)
218 : buildDislikeActivity(url, byActor, accountVideoRate.Video) 216 : buildDislikeActivity(accountVideoRate.url, byActor, accountVideoRate.Video)
219 217
220 return activityPubResponse(activityPubContextify(APObject), res) 218 return activityPubResponse(activityPubContextify(APObject), res)
221 } 219 }
@@ -225,7 +223,7 @@ async function videoController (req: express.Request, res: express.Response) {
225 // We need more attributes 223 // We need more attributes
226 const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(res.locals.onlyVideoWithRights.id) 224 const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(res.locals.onlyVideoWithRights.id)
227 225
228 if (video.url.startsWith(WEBSERVER.URL) === false) return res.redirect(video.url) 226 if (redirectIfNotOwned(video.url, res)) return
229 227
230 // We need captions to render AP object 228 // We need captions to render AP object
231 const captions = await VideoCaptionModel.listVideoCaptions(video.id) 229 const captions = await VideoCaptionModel.listVideoCaptions(video.id)
@@ -245,7 +243,7 @@ async function videoController (req: express.Request, res: express.Response) {
245async function videoAnnounceController (req: express.Request, res: express.Response) { 243async function videoAnnounceController (req: express.Request, res: express.Response) {
246 const share = res.locals.videoShare 244 const share = res.locals.videoShare
247 245
248 if (share.url.startsWith(WEBSERVER.URL) === false) return res.redirect(share.url) 246 if (redirectIfNotOwned(share.url, res)) return
249 247
250 const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) 248 const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined)
251 249
@@ -255,6 +253,8 @@ async function videoAnnounceController (req: express.Request, res: express.Respo
255async function videoAnnouncesController (req: express.Request, res: express.Response) { 253async function videoAnnouncesController (req: express.Request, res: express.Response) {
256 const video = res.locals.onlyImmutableVideo 254 const video = res.locals.onlyImmutableVideo
257 255
256 if (redirectIfNotOwned(video.url, res)) return
257
258 const handler = async (start: number, count: number) => { 258 const handler = async (start: number, count: number) => {
259 const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count) 259 const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count)
260 return { 260 return {
@@ -262,21 +262,27 @@ async function videoAnnouncesController (req: express.Request, res: express.Resp
262 data: result.rows.map(r => r.url) 262 data: result.rows.map(r => r.url)
263 } 263 }
264 } 264 }
265 const json = await activityPubCollectionPagination(getVideoSharesActivityPubUrl(video), handler, req.query.page) 265 const json = await activityPubCollectionPagination(getLocalVideoSharesActivityPubUrl(video), handler, req.query.page)
266 266
267 return activityPubResponse(activityPubContextify(json), res) 267 return activityPubResponse(activityPubContextify(json), res)
268} 268}
269 269
270async function videoLikesController (req: express.Request, res: express.Response) { 270async function videoLikesController (req: express.Request, res: express.Response) {
271 const video = res.locals.onlyImmutableVideo 271 const video = res.locals.onlyImmutableVideo
272 const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video)) 272
273 if (redirectIfNotOwned(video.url, res)) return
274
275 const json = await videoRates(req, 'like', video, getLocalVideoLikesActivityPubUrl(video))
273 276
274 return activityPubResponse(activityPubContextify(json), res) 277 return activityPubResponse(activityPubContextify(json), res)
275} 278}
276 279
277async function videoDislikesController (req: express.Request, res: express.Response) { 280async function videoDislikesController (req: express.Request, res: express.Response) {
278 const video = res.locals.onlyImmutableVideo 281 const video = res.locals.onlyImmutableVideo
279 const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video)) 282
283 if (redirectIfNotOwned(video.url, res)) return
284
285 const json = await videoRates(req, 'dislike', video, getLocalVideoDislikesActivityPubUrl(video))
280 286
281 return activityPubResponse(activityPubContextify(json), res) 287 return activityPubResponse(activityPubContextify(json), res)
282} 288}
@@ -284,6 +290,8 @@ async function videoDislikesController (req: express.Request, res: express.Respo
284async function videoCommentsController (req: express.Request, res: express.Response) { 290async function videoCommentsController (req: express.Request, res: express.Response) {
285 const video = res.locals.onlyImmutableVideo 291 const video = res.locals.onlyImmutableVideo
286 292
293 if (redirectIfNotOwned(video.url, res)) return
294
287 const handler = async (start: number, count: number) => { 295 const handler = async (start: number, count: number) => {
288 const result = await VideoCommentModel.listAndCountByVideoForAP(video, start, count) 296 const result = await VideoCommentModel.listAndCountByVideoForAP(video, start, count)
289 return { 297 return {
@@ -291,7 +299,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
291 data: result.rows.map(r => r.url) 299 data: result.rows.map(r => r.url)
292 } 300 }
293 } 301 }
294 const json = await activityPubCollectionPagination(getVideoCommentsActivityPubUrl(video), handler, req.query.page) 302 const json = await activityPubCollectionPagination(getLocalVideoCommentsActivityPubUrl(video), handler, req.query.page)
295 303
296 return activityPubResponse(activityPubContextify(json), res) 304 return activityPubResponse(activityPubContextify(json), res)
297} 305}
@@ -319,7 +327,7 @@ async function videoChannelFollowingController (req: express.Request, res: expre
319async function videoCommentController (req: express.Request, res: express.Response) { 327async function videoCommentController (req: express.Request, res: express.Response) {
320 const videoComment = res.locals.videoCommentFull 328 const videoComment = res.locals.videoCommentFull
321 329
322 if (videoComment.url.startsWith(WEBSERVER.URL) === false) return res.redirect(videoComment.url) 330 if (redirectIfNotOwned(videoComment.url, res)) return
323 331
324 const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, undefined) 332 const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, undefined)
325 const isPublic = true // Comments are always public 333 const isPublic = true // Comments are always public
@@ -340,7 +348,8 @@ async function videoCommentController (req: express.Request, res: express.Respon
340 348
341async function videoRedundancyController (req: express.Request, res: express.Response) { 349async function videoRedundancyController (req: express.Request, res: express.Response) {
342 const videoRedundancy = res.locals.videoRedundancy 350 const videoRedundancy = res.locals.videoRedundancy
343 if (videoRedundancy.url.startsWith(WEBSERVER.URL) === false) return res.redirect(videoRedundancy.url) 351
352 if (redirectIfNotOwned(videoRedundancy.url, res)) return
344 353
345 const serverActor = await getServerActor() 354 const serverActor = await getServerActor()
346 355
@@ -358,6 +367,8 @@ async function videoRedundancyController (req: express.Request, res: express.Res
358async function videoPlaylistController (req: express.Request, res: express.Response) { 367async function videoPlaylistController (req: express.Request, res: express.Response) {
359 const playlist = res.locals.videoPlaylistFull 368 const playlist = res.locals.videoPlaylistFull
360 369
370 if (redirectIfNotOwned(playlist.url, res)) return
371
361 // We need more attributes 372 // We need more attributes
362 playlist.OwnerAccount = await AccountModel.load(playlist.ownerAccountId) 373 playlist.OwnerAccount = await AccountModel.load(playlist.ownerAccountId)
363 374
@@ -371,6 +382,8 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
371function videoPlaylistElementController (req: express.Request, res: express.Response) { 382function videoPlaylistElementController (req: express.Request, res: express.Response) {
372 const videoPlaylistElement = res.locals.videoPlaylistElementAP 383 const videoPlaylistElement = res.locals.videoPlaylistElementAP
373 384
385 if (redirectIfNotOwned(videoPlaylistElement.url, res)) return
386
374 const json = videoPlaylistElement.toActivityPubObject() 387 const json = videoPlaylistElement.toActivityPubObject()
375 return activityPubResponse(activityPubContextify(json), res) 388 return activityPubResponse(activityPubContextify(json), res)
376} 389}
@@ -411,3 +424,12 @@ function videoRates (req: express.Request, rateType: VideoRateType, video: MVide
411 } 424 }
412 return activityPubCollectionPagination(url, handler, req.query.page) 425 return activityPubCollectionPagination(url, handler, req.query.page)
413} 426}
427
428function redirectIfNotOwned (url: string, res: express.Response) {
429 if (url.startsWith(WEBSERVER.URL) === false) {
430 res.redirect(url)
431 return true
432 }
433
434 return false
435}
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index 23823c9fb..517d1897e 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -165,7 +165,7 @@ async function removeFollowing (req: express.Request, res: express.Response) {
165async function removeOrRejectFollower (req: express.Request, res: express.Response) { 165async function removeOrRejectFollower (req: express.Request, res: express.Response) {
166 const follow = res.locals.follow 166 const follow = res.locals.follow
167 167
168 await sendReject(follow.ActorFollower, follow.ActorFollowing) 168 await sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
169 169
170 await follow.destroy() 170 await follow.destroy()
171 171
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index 41a0e07ff..fb08a63b2 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -1,5 +1,24 @@
1import * as express from 'express' 1import * as express from 'express'
2import { join } from 'path'
3import { getServerActor } from '@server/models/application/application'
4import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
5import { VideoPlaylistCreate } from '../../../shared/models/videos/playlist/video-playlist-create.model'
6import { VideoPlaylistElementCreate } from '../../../shared/models/videos/playlist/video-playlist-element-create.model'
7import { VideoPlaylistElementUpdate } from '../../../shared/models/videos/playlist/video-playlist-element-update.model'
8import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
9import { VideoPlaylistReorder } from '../../../shared/models/videos/playlist/video-playlist-reorder.model'
10import { VideoPlaylistUpdate } from '../../../shared/models/videos/playlist/video-playlist-update.model'
11import { resetSequelizeInstance } from '../../helpers/database-utils'
12import { buildNSFWFilter, createReqFiles } from '../../helpers/express-utils'
13import { logger } from '../../helpers/logger'
2import { getFormattedObjects } from '../../helpers/utils' 14import { getFormattedObjects } from '../../helpers/utils'
15import { CONFIG } from '../../initializers/config'
16import { MIMETYPES, VIDEO_PLAYLIST_PRIVACIES } from '../../initializers/constants'
17import { sequelizeTypescript } from '../../initializers/database'
18import { sendCreateVideoPlaylist, sendDeleteVideoPlaylist, sendUpdateVideoPlaylist } from '../../lib/activitypub/send'
19import { getLocalVideoPlaylistActivityPubUrl, getLocalVideoPlaylistElementActivityPubUrl } from '../../lib/activitypub/url'
20import { JobQueue } from '../../lib/job-queue'
21import { createPlaylistMiniatureFromExisting } from '../../lib/thumbnail'
3import { 22import {
4 asyncMiddleware, 23 asyncMiddleware,
5 asyncRetryTransactionMiddleware, 24 asyncRetryTransactionMiddleware,
@@ -10,11 +29,6 @@ import {
10 setDefaultSort 29 setDefaultSort
11} from '../../middlewares' 30} from '../../middlewares'
12import { videoPlaylistsSortValidator } from '../../middlewares/validators' 31import { videoPlaylistsSortValidator } from '../../middlewares/validators'
13import { buildNSFWFilter, createReqFiles } from '../../helpers/express-utils'
14import { MIMETYPES, VIDEO_PLAYLIST_PRIVACIES } from '../../initializers/constants'
15import { logger } from '../../helpers/logger'
16import { resetSequelizeInstance } from '../../helpers/database-utils'
17import { VideoPlaylistModel } from '../../models/video/video-playlist'
18import { 32import {
19 commonVideoPlaylistFiltersValidator, 33 commonVideoPlaylistFiltersValidator,
20 videoPlaylistsAddValidator, 34 videoPlaylistsAddValidator,
@@ -25,23 +39,9 @@ import {
25 videoPlaylistsUpdateOrRemoveVideoValidator, 39 videoPlaylistsUpdateOrRemoveVideoValidator,
26 videoPlaylistsUpdateValidator 40 videoPlaylistsUpdateValidator
27} from '../../middlewares/validators/videos/video-playlists' 41} from '../../middlewares/validators/videos/video-playlists'
28import { VideoPlaylistCreate } from '../../../shared/models/videos/playlist/video-playlist-create.model'
29import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
30import { join } from 'path'
31import { sendCreateVideoPlaylist, sendDeleteVideoPlaylist, sendUpdateVideoPlaylist } from '../../lib/activitypub/send'
32import { getVideoPlaylistActivityPubUrl, getVideoPlaylistElementActivityPubUrl } from '../../lib/activitypub/url'
33import { VideoPlaylistUpdate } from '../../../shared/models/videos/playlist/video-playlist-update.model'
34import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
35import { VideoPlaylistElementCreate } from '../../../shared/models/videos/playlist/video-playlist-element-create.model'
36import { VideoPlaylistElementUpdate } from '../../../shared/models/videos/playlist/video-playlist-element-update.model'
37import { AccountModel } from '../../models/account/account' 42import { AccountModel } from '../../models/account/account'
38import { VideoPlaylistReorder } from '../../../shared/models/videos/playlist/video-playlist-reorder.model' 43import { VideoPlaylistModel } from '../../models/video/video-playlist'
39import { JobQueue } from '../../lib/job-queue' 44import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
40import { CONFIG } from '../../initializers/config'
41import { sequelizeTypescript } from '../../initializers/database'
42import { createPlaylistMiniatureFromExisting } from '../../lib/thumbnail'
43import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
44import { getServerActor } from '@server/models/application/application'
45 45
46const reqThumbnailFile = createReqFiles([ 'thumbnailfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { thumbnailfile: CONFIG.STORAGE.TMP_DIR }) 46const reqThumbnailFile = createReqFiles([ 'thumbnailfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { thumbnailfile: CONFIG.STORAGE.TMP_DIR })
47 47
@@ -161,7 +161,7 @@ async function addVideoPlaylist (req: express.Request, res: express.Response) {
161 ownerAccountId: user.Account.id 161 ownerAccountId: user.Account.id
162 }) as MVideoPlaylistFull 162 }) as MVideoPlaylistFull
163 163
164 videoPlaylist.url = getVideoPlaylistActivityPubUrl(videoPlaylist) // We use the UUID, so set the URL after building the object 164 videoPlaylist.url = getLocalVideoPlaylistActivityPubUrl(videoPlaylist) // We use the UUID, so set the URL after building the object
165 165
166 if (videoPlaylistInfo.videoChannelId) { 166 if (videoPlaylistInfo.videoChannelId) {
167 const videoChannel = res.locals.videoChannel 167 const videoChannel = res.locals.videoChannel
@@ -304,7 +304,7 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
304 videoId: video.id 304 videoId: video.id
305 }, { transaction: t }) 305 }, { transaction: t })
306 306
307 playlistElement.url = getVideoPlaylistElementActivityPubUrl(videoPlaylist, playlistElement) 307 playlistElement.url = getLocalVideoPlaylistElementActivityPubUrl(videoPlaylist, playlistElement)
308 await playlistElement.save({ transaction: t }) 308 await playlistElement.save({ transaction: t })
309 309
310 videoPlaylist.changed('updatedAt', true) 310 videoPlaylist.changed('updatedAt', true)
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts
index 5840cd063..bc5fea7aa 100644
--- a/server/controllers/api/videos/import.ts
+++ b/server/controllers/api/videos/import.ts
@@ -28,7 +28,7 @@ import { getYoutubeDLInfo, getYoutubeDLSubs, YoutubeDLInfo } from '../../../help
28import { CONFIG } from '../../../initializers/config' 28import { CONFIG } from '../../../initializers/config'
29import { MIMETYPES } from '../../../initializers/constants' 29import { MIMETYPES } from '../../../initializers/constants'
30import { sequelizeTypescript } from '../../../initializers/database' 30import { sequelizeTypescript } from '../../../initializers/database'
31import { getVideoActivityPubUrl } from '../../../lib/activitypub/url' 31import { getLocalVideoActivityPubUrl } from '../../../lib/activitypub/url'
32import { JobQueue } from '../../../lib/job-queue/job-queue' 32import { JobQueue } from '../../../lib/job-queue/job-queue'
33import { createVideoMiniatureFromExisting, createVideoMiniatureFromUrl } from '../../../lib/thumbnail' 33import { createVideoMiniatureFromExisting, createVideoMiniatureFromUrl } from '../../../lib/thumbnail'
34import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' 34import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist'
@@ -250,7 +250,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
250 originallyPublishedAt: body.originallyPublishedAt || importData.originallyPublishedAt 250 originallyPublishedAt: body.originallyPublishedAt || importData.originallyPublishedAt
251 } 251 }
252 const video = new VideoModel(videoData) 252 const video = new VideoModel(videoData)
253 video.url = getVideoActivityPubUrl(video) 253 video.url = getLocalVideoActivityPubUrl(video)
254 254
255 return video 255 return video
256} 256}
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index bfebc54ed..b5ff2e72e 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -5,7 +5,7 @@ import toInt from 'validator/lib/toInt'
5import { addOptimizeOrMergeAudioJob } from '@server/helpers/video' 5import { addOptimizeOrMergeAudioJob } from '@server/helpers/video'
6import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' 6import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
7import { changeVideoChannelShare } from '@server/lib/activitypub/share' 7import { changeVideoChannelShare } from '@server/lib/activitypub/share'
8import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' 8import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
9import { LiveManager } from '@server/lib/live-manager' 9import { LiveManager } from '@server/lib/live-manager'
10import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' 10import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
11import { getVideoFilePath } from '@server/lib/video-paths' 11import { getVideoFilePath } from '@server/lib/video-paths'
@@ -189,7 +189,7 @@ async function addVideo (req: express.Request, res: express.Response) {
189 videoData.duration = videoPhysicalFile['duration'] // duration was added by a previous middleware 189 videoData.duration = videoPhysicalFile['duration'] // duration was added by a previous middleware
190 190
191 const video = new VideoModel(videoData) as MVideoFullLight 191 const video = new VideoModel(videoData) as MVideoFullLight
192 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object 192 video.url = getLocalVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object
193 193
194 const videoFile = new VideoFileModel({ 194 const videoFile = new VideoFileModel({
195 extname: extname(videoPhysicalFile.filename), 195 extname: extname(videoPhysicalFile.filename),
diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts
index d438b6f3a..a6f00c1bd 100644
--- a/server/controllers/api/videos/live.ts
+++ b/server/controllers/api/videos/live.ts
@@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid'
3import { createReqFiles } from '@server/helpers/express-utils' 3import { createReqFiles } from '@server/helpers/express-utils'
4import { CONFIG } from '@server/initializers/config' 4import { CONFIG } from '@server/initializers/config'
5import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants' 5import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants'
6import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' 6import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
7import { federateVideoIfNeeded } from '@server/lib/activitypub/videos' 7import { federateVideoIfNeeded } from '@server/lib/activitypub/videos'
8import { Hooks } from '@server/lib/plugins/hooks' 8import { Hooks } from '@server/lib/plugins/hooks'
9import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' 9import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
@@ -86,7 +86,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) {
86 videoData.duration = 0 86 videoData.duration = 0
87 87
88 const video = new VideoModel(videoData) as MVideoDetails 88 const video = new VideoModel(videoData) as MVideoDetails
89 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object 89 video.url = getLocalVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object
90 90
91 const videoLive = new VideoLiveModel() 91 const videoLive = new VideoLiveModel()
92 videoLive.saveReplay = videoInfo.saveReplay || false 92 videoLive.saveReplay = videoInfo.saveReplay || false
diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts
index 3ee365289..df1eddb4f 100644
--- a/server/controllers/api/videos/rate.ts
+++ b/server/controllers/api/videos/rate.ts
@@ -2,7 +2,7 @@ import * as express from 'express'
2import { UserVideoRateUpdate } from '../../../../shared' 2import { UserVideoRateUpdate } from '../../../../shared'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { VIDEO_RATE_TYPES } from '../../../initializers/constants' 4import { VIDEO_RATE_TYPES } from '../../../initializers/constants'
5import { getRateUrl, sendVideoRateChange } from '../../../lib/activitypub/video-rates' 5import { getLocalRateUrl, sendVideoRateChange } from '../../../lib/activitypub/video-rates'
6import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoUpdateRateValidator } from '../../../middlewares' 6import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoUpdateRateValidator } from '../../../middlewares'
7import { AccountModel } from '../../../models/account/account' 7import { AccountModel } from '../../../models/account/account'
8import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 8import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
@@ -52,7 +52,7 @@ async function rateVideo (req: express.Request, res: express.Response) {
52 await previousRate.destroy(sequelizeOptions) 52 await previousRate.destroy(sequelizeOptions)
53 } else { // Update previous rate 53 } else { // Update previous rate
54 previousRate.type = rateType 54 previousRate.type = rateType
55 previousRate.url = getRateUrl(rateType, userAccount.Actor, videoInstance) 55 previousRate.url = getLocalRateUrl(rateType, userAccount.Actor, videoInstance)
56 await previousRate.save(sequelizeOptions) 56 await previousRate.save(sequelizeOptions)
57 } 57 }
58 } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate 58 } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
@@ -60,7 +60,7 @@ async function rateVideo (req: express.Request, res: express.Response) {
60 accountId: accountInstance.id, 60 accountId: accountInstance.id,
61 videoId: videoInstance.id, 61 videoId: videoInstance.id,
62 type: rateType, 62 type: rateType,
63 url: getRateUrl(rateType, userAccount.Actor, videoInstance) 63 url: getLocalRateUrl(rateType, userAccount.Actor, videoInstance)
64 } 64 }
65 65
66 await AccountVideoRateModel.create(query, sequelizeOptions) 66 await AccountVideoRateModel.create(query, sequelizeOptions)
diff --git a/server/initializers/migrations/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts
index 05fd37406..49309286c 100644
--- a/server/initializers/migrations/0100-activitypub.ts
+++ b/server/initializers/migrations/0100-activitypub.ts
@@ -1,7 +1,7 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' 2import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
3import { shareVideoByServerAndChannel } from '../../lib/activitypub/share' 3import { shareVideoByServerAndChannel } from '../../lib/activitypub/share'
4import { getVideoActivityPubUrl, getVideoChannelActivityPubUrl } from '../../lib/activitypub/url' 4import { getLocalVideoActivityPubUrl, getLocalVideoChannelActivityPubUrl } from '../../lib/activitypub/url'
5import { createLocalAccountWithoutKeys } from '../../lib/user' 5import { createLocalAccountWithoutKeys } from '../../lib/user'
6import { ApplicationModel } from '../../models/application/application' 6import { ApplicationModel } from '../../models/application/application'
7import { SERVER_ACTOR_NAME } from '../constants' 7import { SERVER_ACTOR_NAME } from '../constants'
@@ -132,7 +132,7 @@ async function up (utils: {
132 132
133 const videos = await db.Video.findAll() 133 const videos = await db.Video.findAll()
134 for (const video of videos) { 134 for (const video of videos) {
135 video.url = getVideoActivityPubUrl(video) 135 video.url = getLocalVideoActivityPubUrl(video)
136 await video.save() 136 await video.save()
137 } 137 }
138 138
@@ -151,7 +151,7 @@ async function up (utils: {
151 151
152 const videoChannels = await db.VideoChannel.findAll() 152 const videoChannels = await db.VideoChannel.findAll()
153 for (const videoChannel of videoChannels) { 153 for (const videoChannel of videoChannels) {
154 videoChannel.url = getVideoChannelActivityPubUrl(videoChannel) 154 videoChannel.url = getLocalVideoChannelActivityPubUrl(videoChannel)
155 await videoChannel.save() 155 await videoChannel.save()
156 } 156 }
157 157
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts
index 0cd204501..635c8bfcc 100644
--- a/server/lib/activitypub/process/process-dislike.ts
+++ b/server/lib/activitypub/process/process-dislike.ts
@@ -3,11 +3,10 @@ import { DislikeObject } from '../../../../shared/models/activitypub/objects'
3import { retryTransactionWrapper } from '../../../helpers/database-utils' 3import { retryTransactionWrapper } from '../../../helpers/database-utils'
4import { sequelizeTypescript } from '../../../initializers/database' 4import { sequelizeTypescript } from '../../../initializers/database'
5import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 5import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
7import { forwardVideoRelatedActivity } from '../send/utils'
8import { getVideoDislikeActivityPubUrl } from '../url'
9import { APProcessorOptions } from '../../../types/activitypub-processor.model' 6import { APProcessorOptions } from '../../../types/activitypub-processor.model'
10import { MActorSignature } from '../../../types/models' 7import { MActorSignature } from '../../../types/models'
8import { forwardVideoRelatedActivity } from '../send/utils'
9import { getOrCreateVideoAndAccountAndChannel } from '../videos'
11 10
12async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { 11async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) {
13 const { activity, byActor } = options 12 const { activity, byActor } = options
@@ -23,7 +22,10 @@ export {
23// --------------------------------------------------------------------------- 22// ---------------------------------------------------------------------------
24 23
25async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) { 24async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) {
26 const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object 25 const dislikeObject = activity.type === 'Dislike'
26 ? activity.object
27 : (activity.object as DislikeObject).object
28
27 const byAccount = byActor.Account 29 const byAccount = byActor.Account
28 30
29 if (!byAccount) throw new Error('Cannot create dislike with the non account actor ' + byActor.url) 31 if (!byAccount) throw new Error('Cannot create dislike with the non account actor ' + byActor.url)
@@ -31,9 +33,7 @@ async function processDislike (activity: ActivityCreate | ActivityDislike, byAct
31 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: dislikeObject }) 33 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: dislikeObject })
32 34
33 return sequelizeTypescript.transaction(async t => { 35 return sequelizeTypescript.transaction(async t => {
34 const url = getVideoDislikeActivityPubUrl(byActor, video) 36 const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, activity.id)
35
36 const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, url)
37 if (existingRate && existingRate.type === 'dislike') return 37 if (existingRate && existingRate.type === 'dislike') return
38 38
39 await video.increment('dislikes', { transaction: t }) 39 await video.increment('dislikes', { transaction: t })
@@ -46,7 +46,7 @@ async function processDislike (activity: ActivityCreate | ActivityDislike, byAct
46 rate.type = 'dislike' 46 rate.type = 'dislike'
47 rate.videoId = video.id 47 rate.videoId = video.id
48 rate.accountId = byAccount.id 48 rate.accountId = byAccount.id
49 rate.url = url 49 rate.url = activity.id
50 50
51 await rate.save({ transaction: t }) 51 await rate.save({ transaction: t })
52 52
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts
index 7eb7e828d..076ad9cf4 100644
--- a/server/lib/activitypub/process/process-follow.ts
+++ b/server/lib/activitypub/process/process-follow.ts
@@ -15,9 +15,11 @@ import { getServerActor } from '@server/models/application/application'
15 15
16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { 16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) {
17 const { activity, byActor } = options 17 const { activity, byActor } = options
18 const activityObject = getAPId(activity.object)
19 18
20 return retryTransactionWrapper(processFollow, byActor, activityObject) 19 const activityId = activity.id
20 const objectId = getAPId(activity.object)
21
22 return retryTransactionWrapper(processFollow, byActor, activityId, objectId)
21} 23}
22 24
23// --------------------------------------------------------------------------- 25// ---------------------------------------------------------------------------
@@ -28,7 +30,7 @@ export {
28 30
29// --------------------------------------------------------------------------- 31// ---------------------------------------------------------------------------
30 32
31async function processFollow (byActor: MActorSignature, targetActorURL: string) { 33async function processFollow (byActor: MActorSignature, activityId: string, targetActorURL: string) {
32 const { actorFollow, created, isFollowingInstance, targetActor } = await sequelizeTypescript.transaction(async t => { 34 const { actorFollow, created, isFollowingInstance, targetActor } = await sequelizeTypescript.transaction(async t => {
33 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) 35 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t)
34 36
@@ -41,7 +43,7 @@ async function processFollow (byActor: MActorSignature, targetActorURL: string)
41 if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { 43 if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) {
42 logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) 44 logger.info('Rejecting %s because instance followers are disabled.', targetActor.url)
43 45
44 await sendReject(byActor, targetActor) 46 await sendReject(activityId, byActor, targetActor)
45 47
46 return { actorFollow: undefined as MActorFollowActors } 48 return { actorFollow: undefined as MActorFollowActors }
47 } 49 }
@@ -54,7 +56,11 @@ async function processFollow (byActor: MActorSignature, targetActorURL: string)
54 defaults: { 56 defaults: {
55 actorId: byActor.id, 57 actorId: byActor.id,
56 targetActorId: targetActor.id, 58 targetActorId: targetActor.id,
57 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' 59 url: activityId,
60
61 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL
62 ? 'pending'
63 : 'accepted'
58 }, 64 },
59 transaction: t 65 transaction: t
60 }) 66 })
diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts
index b800a5618..6acc097b1 100644
--- a/server/lib/activitypub/process/process-like.ts
+++ b/server/lib/activitypub/process/process-like.ts
@@ -1,13 +1,12 @@
1import { ActivityLike } from '../../../../shared/models/activitypub' 1import { ActivityLike } from '../../../../shared/models/activitypub'
2import { getAPId } from '../../../helpers/activitypub'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 3import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { sequelizeTypescript } from '../../../initializers/database' 4import { sequelizeTypescript } from '../../../initializers/database'
4import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 5import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
5import { forwardVideoRelatedActivity } from '../send/utils'
6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
7import { getVideoLikeActivityPubUrl } from '../url'
8import { getAPId } from '../../../helpers/activitypub'
9import { APProcessorOptions } from '../../../types/activitypub-processor.model' 6import { APProcessorOptions } from '../../../types/activitypub-processor.model'
10import { MActorSignature } from '../../../types/models' 7import { MActorSignature } from '../../../types/models'
8import { forwardVideoRelatedActivity } from '../send/utils'
9import { getOrCreateVideoAndAccountAndChannel } from '../videos'
11 10
12async function processLikeActivity (options: APProcessorOptions<ActivityLike>) { 11async function processLikeActivity (options: APProcessorOptions<ActivityLike>) {
13 const { activity, byActor } = options 12 const { activity, byActor } = options
@@ -31,9 +30,7 @@ async function processLikeVideo (byActor: MActorSignature, activity: ActivityLik
31 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoUrl }) 30 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoUrl })
32 31
33 return sequelizeTypescript.transaction(async t => { 32 return sequelizeTypescript.transaction(async t => {
34 const url = getVideoLikeActivityPubUrl(byActor, video) 33 const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, activity.id)
35
36 const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, url)
37 if (existingRate && existingRate.type === 'like') return 34 if (existingRate && existingRate.type === 'like') return
38 35
39 if (existingRate && existingRate.type === 'dislike') { 36 if (existingRate && existingRate.type === 'dislike') {
@@ -46,7 +43,7 @@ async function processLikeVideo (byActor: MActorSignature, activity: ActivityLik
46 rate.type = 'like' 43 rate.type = 'like'
47 rate.videoId = video.id 44 rate.videoId = video.id
48 rate.accountId = byAccount.id 45 rate.accountId = byAccount.id
49 rate.url = url 46 rate.url = activity.id
50 47
51 await rate.save({ transaction: t }) 48 await rate.save({ transaction: t })
52 49
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts
index 50e192bdd..bb387e2c0 100644
--- a/server/lib/activitypub/send/send-accept.ts
+++ b/server/lib/activitypub/send/send-accept.ts
@@ -1,9 +1,9 @@
1import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub' 1import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub'
2import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url'
3import { unicastTo } from './utils'
4import { buildFollowActivity } from './send-follow'
5import { logger } from '../../../helpers/logger' 2import { logger } from '../../../helpers/logger'
6import { MActor, MActorFollowActors } from '../../../types/models' 3import { MActor, MActorFollowActors } from '../../../types/models'
4import { getLocalActorFollowAcceptActivityPubUrl } from '../url'
5import { buildFollowActivity } from './send-follow'
6import { unicastTo } from './utils'
7 7
8function sendAccept (actorFollow: MActorFollowActors) { 8function sendAccept (actorFollow: MActorFollowActors) {
9 const follower = actorFollow.ActorFollower 9 const follower = actorFollow.ActorFollower
@@ -16,10 +16,9 @@ function sendAccept (actorFollow: MActorFollowActors) {
16 16
17 logger.info('Creating job to accept follower %s.', follower.url) 17 logger.info('Creating job to accept follower %s.', follower.url)
18 18
19 const followUrl = getActorFollowActivityPubUrl(follower, me) 19 const followData = buildFollowActivity(actorFollow.url, follower, me)
20 const followData = buildFollowActivity(followUrl, follower, me)
21 20
22 const url = getActorFollowAcceptActivityPubUrl(actorFollow) 21 const url = getLocalActorFollowAcceptActivityPubUrl(actorFollow)
23 const data = buildAcceptActivity(url, me, followData) 22 const data = buildAcceptActivity(url, me, followData)
24 23
25 return unicastTo(data, me, follower.inboxUrl) 24 return unicastTo(data, me, follower.inboxUrl)
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts
index 1bb7dc937..274230535 100644
--- a/server/lib/activitypub/send/send-dislike.ts
+++ b/server/lib/activitypub/send/send-dislike.ts
@@ -1,5 +1,5 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { getVideoDislikeActivityPubUrl } from '../url' 2import { getVideoDislikeActivityPubUrlByLocalActor } from '../url'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { ActivityAudience, ActivityDislike } from '../../../../shared/models/activitypub' 4import { ActivityAudience, ActivityDislike } from '../../../../shared/models/activitypub'
5import { sendVideoRelatedActivity } from './utils' 5import { sendVideoRelatedActivity } from './utils'
@@ -10,7 +10,7 @@ function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction
10 logger.info('Creating job to dislike %s.', video.url) 10 logger.info('Creating job to dislike %s.', video.url)
11 11
12 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
13 const url = getVideoDislikeActivityPubUrl(byActor, video) 13 const url = getVideoDislikeActivityPubUrlByLocalActor(byActor, video)
14 14
15 return buildDislikeActivity(url, byActor, video, audience) 15 return buildDislikeActivity(url, byActor, video, audience)
16 } 16 }
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts
index 821637ec8..b0483b5a0 100644
--- a/server/lib/activitypub/send/send-flag.ts
+++ b/server/lib/activitypub/send/send-flag.ts
@@ -3,13 +3,13 @@ import { ActivityAudience, ActivityFlag } from '../../../../shared/models/activi
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { MAbuseAP, MAccountLight, MActor } from '../../../types/models' 4import { MAbuseAP, MAccountLight, MActor } from '../../../types/models'
5import { audiencify, getAudience } from '../audience' 5import { audiencify, getAudience } from '../audience'
6import { getAbuseActivityPubUrl } from '../url' 6import { getLocalAbuseActivityPubUrl } from '../url'
7import { unicastTo } from './utils' 7import { unicastTo } from './utils'
8 8
9function sendAbuse (byActor: MActor, abuse: MAbuseAP, flaggedAccount: MAccountLight, t: Transaction) { 9function sendAbuse (byActor: MActor, abuse: MAbuseAP, flaggedAccount: MAccountLight, t: Transaction) {
10 if (!flaggedAccount.Actor.serverId) return // Local user 10 if (!flaggedAccount.Actor.serverId) return // Local user
11 11
12 const url = getAbuseActivityPubUrl(abuse) 12 const url = getLocalAbuseActivityPubUrl(abuse)
13 13
14 logger.info('Creating job to send abuse %s.', url) 14 logger.info('Creating job to send abuse %s.', url)
15 15
diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts
index 08f1d83f9..9219640dd 100644
--- a/server/lib/activitypub/send/send-follow.ts
+++ b/server/lib/activitypub/send/send-follow.ts
@@ -1,9 +1,8 @@
1import { Transaction } from 'sequelize'
1import { ActivityFollow } from '../../../../shared/models/activitypub' 2import { ActivityFollow } from '../../../../shared/models/activitypub'
2import { getActorFollowActivityPubUrl } from '../url'
3import { unicastTo } from './utils'
4import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
5import { Transaction } from 'sequelize'
6import { MActor, MActorFollowActors } from '../../../types/models' 4import { MActor, MActorFollowActors } from '../../../types/models'
5import { unicastTo } from './utils'
7 6
8function sendFollow (actorFollow: MActorFollowActors, t: Transaction) { 7function sendFollow (actorFollow: MActorFollowActors, t: Transaction) {
9 const me = actorFollow.ActorFollower 8 const me = actorFollow.ActorFollower
@@ -14,8 +13,7 @@ function sendFollow (actorFollow: MActorFollowActors, t: Transaction) {
14 13
15 logger.info('Creating job to send follow request to %s.', following.url) 14 logger.info('Creating job to send follow request to %s.', following.url)
16 15
17 const url = getActorFollowActivityPubUrl(me, following) 16 const data = buildFollowActivity(actorFollow.url, me, following)
18 const data = buildFollowActivity(url, me, following)
19 17
20 t.afterCommit(() => unicastTo(data, me, following.inboxUrl)) 18 t.afterCommit(() => unicastTo(data, me, following.inboxUrl))
21} 19}
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts
index 29fcfc404..ed6dfcf56 100644
--- a/server/lib/activitypub/send/send-like.ts
+++ b/server/lib/activitypub/send/send-like.ts
@@ -1,6 +1,6 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityLike } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityLike } from '../../../../shared/models/activitypub'
3import { getVideoLikeActivityPubUrl } from '../url' 3import { getVideoLikeActivityPubUrlByLocalActor } from '../url'
4import { sendVideoRelatedActivity } from './utils' 4import { sendVideoRelatedActivity } from './utils'
5import { audiencify, getAudience } from '../audience' 5import { audiencify, getAudience } from '../audience'
6import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
@@ -10,7 +10,7 @@ function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
10 logger.info('Creating job to like %s.', video.url) 10 logger.info('Creating job to like %s.', video.url)
11 11
12 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
13 const url = getVideoLikeActivityPubUrl(byActor, video) 13 const url = getVideoLikeActivityPubUrlByLocalActor(byActor, video)
14 14
15 return buildLikeActivity(url, byActor, video, audience) 15 return buildLikeActivity(url, byActor, video, audience)
16 } 16 }
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts
index befbcb8da..8d74a7848 100644
--- a/server/lib/activitypub/send/send-reject.ts
+++ b/server/lib/activitypub/send/send-reject.ts
@@ -1,11 +1,11 @@
1import { ActivityFollow, ActivityReject } from '../../../../shared/models/activitypub' 1import { ActivityFollow, ActivityReject } from '../../../../shared/models/activitypub'
2import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from '../url'
3import { unicastTo } from './utils'
4import { buildFollowActivity } from './send-follow'
5import { logger } from '../../../helpers/logger' 2import { logger } from '../../../helpers/logger'
6import { MActor } from '../../../types/models' 3import { MActor } from '../../../types/models'
4import { getLocalActorFollowRejectActivityPubUrl } from '../url'
5import { buildFollowActivity } from './send-follow'
6import { unicastTo } from './utils'
7 7
8function sendReject (follower: MActor, following: MActor) { 8function sendReject (followUrl: string, follower: MActor, following: MActor) {
9 if (!follower.serverId) { // This should never happen 9 if (!follower.serverId) { // This should never happen
10 logger.warn('Do not sending reject to local follower.') 10 logger.warn('Do not sending reject to local follower.')
11 return 11 return
@@ -13,10 +13,9 @@ function sendReject (follower: MActor, following: MActor) {
13 13
14 logger.info('Creating job to reject follower %s.', follower.url) 14 logger.info('Creating job to reject follower %s.', follower.url)
15 15
16 const followUrl = getActorFollowActivityPubUrl(follower, following)
17 const followData = buildFollowActivity(followUrl, follower, following) 16 const followData = buildFollowActivity(followUrl, follower, following)
18 17
19 const url = getActorFollowRejectActivityPubUrl(follower, following) 18 const url = getLocalActorFollowRejectActivityPubUrl(follower, following)
20 const data = buildRejectActivity(url, following, followData) 19 const data = buildRejectActivity(url, following, followData)
21 20
22 return unicastTo(data, following, follower.inboxUrl) 21 return unicastTo(data, following, follower.inboxUrl)
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts
index 6ed343300..352c158fd 100644
--- a/server/lib/activitypub/send/send-undo.ts
+++ b/server/lib/activitypub/send/send-undo.ts
@@ -8,18 +8,11 @@ import {
8 ActivityLike, 8 ActivityLike,
9 ActivityUndo 9 ActivityUndo
10} from '../../../../shared/models/activitypub' 10} from '../../../../shared/models/activitypub'
11import { VideoModel } from '../../../models/video/video'
12import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url'
13import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
14import { audiencify, getAudience } from '../audience'
15import { buildCreateActivity } from './send-create'
16import { buildFollowActivity } from './send-follow'
17import { buildLikeActivity } from './send-like'
18import { buildAnnounceWithVideoAudience } from './send-announce'
19import { logger } from '../../../helpers/logger' 11import { logger } from '../../../helpers/logger'
20import { buildDislikeActivity } from './send-dislike' 12import { VideoModel } from '../../../models/video/video'
21import { 13import {
22 MActor, MActorAudience, 14 MActor,
15 MActorAudience,
23 MActorFollowActors, 16 MActorFollowActors,
24 MActorLight, 17 MActorLight,
25 MVideo, 18 MVideo,
@@ -27,6 +20,14 @@ import {
27 MVideoRedundancyVideo, 20 MVideoRedundancyVideo,
28 MVideoShare 21 MVideoShare
29} from '../../../types/models' 22} from '../../../types/models'
23import { audiencify, getAudience } from '../audience'
24import { getUndoActivityPubUrl, getVideoDislikeActivityPubUrlByLocalActor, getVideoLikeActivityPubUrlByLocalActor } from '../url'
25import { buildAnnounceWithVideoAudience } from './send-announce'
26import { buildCreateActivity } from './send-create'
27import { buildDislikeActivity } from './send-dislike'
28import { buildFollowActivity } from './send-follow'
29import { buildLikeActivity } from './send-like'
30import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
30 31
31function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { 32function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
32 const me = actorFollow.ActorFollower 33 const me = actorFollow.ActorFollower
@@ -37,10 +38,9 @@ function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
37 38
38 logger.info('Creating job to send an unfollow request to %s.', following.url) 39 logger.info('Creating job to send an unfollow request to %s.', following.url)
39 40
40 const followUrl = getActorFollowActivityPubUrl(me, following) 41 const undoUrl = getUndoActivityPubUrl(actorFollow.url)
41 const undoUrl = getUndoActivityPubUrl(followUrl)
42 42
43 const followActivity = buildFollowActivity(followUrl, me, following) 43 const followActivity = buildFollowActivity(actorFollow.url, me, following)
44 const undoActivity = undoActivityData(undoUrl, me, followActivity) 44 const undoActivity = undoActivityData(undoUrl, me, followActivity)
45 45
46 t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl)) 46 t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl))
@@ -61,7 +61,7 @@ async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare,
61async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { 61async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
62 logger.info('Creating job to undo a like of video %s.', video.url) 62 logger.info('Creating job to undo a like of video %s.', video.url)
63 63
64 const likeUrl = getVideoLikeActivityPubUrl(byActor, video) 64 const likeUrl = getVideoLikeActivityPubUrlByLocalActor(byActor, video)
65 const likeActivity = buildLikeActivity(likeUrl, byActor, video) 65 const likeActivity = buildLikeActivity(likeUrl, byActor, video)
66 66
67 return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) 67 return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t })
@@ -70,7 +70,7 @@ async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Tran
70async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { 70async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
71 logger.info('Creating job to undo a dislike of video %s.', video.url) 71 logger.info('Creating job to undo a dislike of video %s.', video.url)
72 72
73 const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) 73 const dislikeUrl = getVideoDislikeActivityPubUrlByLocalActor(byActor, video)
74 const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video) 74 const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video)
75 75
76 return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t }) 76 return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t })
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts
index 3358188a2..9254dc7c5 100644
--- a/server/lib/activitypub/send/send-view.ts
+++ b/server/lib/activitypub/send/send-view.ts
@@ -1,17 +1,17 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { MActorAudience, MVideoImmutable, MVideoUrl } from '@server/types/models'
2import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub' 3import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub'
4import { logger } from '../../../helpers/logger'
3import { ActorModel } from '../../../models/activitypub/actor' 5import { ActorModel } from '../../../models/activitypub/actor'
4import { getVideoLikeActivityPubUrl } from '../url'
5import { sendVideoRelatedActivity } from './utils'
6import { audiencify, getAudience } from '../audience' 6import { audiencify, getAudience } from '../audience'
7import { logger } from '../../../helpers/logger' 7import { getLocalVideoViewActivityPubUrl } from '../url'
8import { MActorAudience, MVideoImmutable, MVideoUrl } from '@server/types/models' 8import { sendVideoRelatedActivity } from './utils'
9 9
10async function sendView (byActor: ActorModel, video: MVideoImmutable, t: Transaction) { 10async function sendView (byActor: ActorModel, video: MVideoImmutable, t: Transaction) {
11 logger.info('Creating job to send view of %s.', video.url) 11 logger.info('Creating job to send view of %s.', video.url)
12 12
13 const activityBuilder = (audience: ActivityAudience) => { 13 const activityBuilder = (audience: ActivityAudience) => {
14 const url = getVideoLikeActivityPubUrl(byActor, video) 14 const url = getLocalVideoViewActivityPubUrl(byActor, video)
15 15
16 return buildViewActivity(url, byActor, video, audience) 16 return buildViewActivity(url, byActor, video, audience)
17 } 17 }
diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts
index 5e426f5db..1f8a8f3c4 100644
--- a/server/lib/activitypub/share.ts
+++ b/server/lib/activitypub/share.ts
@@ -1,7 +1,7 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { VideoShareModel } from '../../models/video/video-share' 2import { VideoShareModel } from '../../models/video/video-share'
3import { sendUndoAnnounce, sendVideoAnnounce } from './send' 3import { sendUndoAnnounce, sendVideoAnnounce } from './send'
4import { getVideoAnnounceActivityPubUrl } from './url' 4import { getLocalVideoAnnounceActivityPubUrl } from './url'
5import * as Bluebird from 'bluebird' 5import * as Bluebird from 'bluebird'
6import { doRequest } from '../../helpers/requests' 6import { doRequest } from '../../helpers/requests'
7import { getOrCreateActorAndServerAndModel } from './actor' 7import { getOrCreateActorAndServerAndModel } from './actor'
@@ -74,7 +74,7 @@ export {
74async function shareByServer (video: MVideo, t: Transaction) { 74async function shareByServer (video: MVideo, t: Transaction) {
75 const serverActor = await getServerActor() 75 const serverActor = await getServerActor()
76 76
77 const serverShareUrl = getVideoAnnounceActivityPubUrl(serverActor, video) 77 const serverShareUrl = getLocalVideoAnnounceActivityPubUrl(serverActor, video)
78 const [ serverShare ] = await VideoShareModel.findOrCreate({ 78 const [ serverShare ] = await VideoShareModel.findOrCreate({
79 defaults: { 79 defaults: {
80 actorId: serverActor.id, 80 actorId: serverActor.id,
@@ -91,7 +91,7 @@ async function shareByServer (video: MVideo, t: Transaction) {
91} 91}
92 92
93async function shareByVideoChannel (video: MVideoAccountLight, t: Transaction) { 93async function shareByVideoChannel (video: MVideoAccountLight, t: Transaction) {
94 const videoChannelShareUrl = getVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video) 94 const videoChannelShareUrl = getLocalVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video)
95 const [ videoChannelShare ] = await VideoShareModel.findOrCreate({ 95 const [ videoChannelShare ] = await VideoShareModel.findOrCreate({
96 defaults: { 96 defaults: {
97 actorId: video.VideoChannel.actorId, 97 actorId: video.VideoChannel.actorId,
diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts
index 58030be2c..ad6a1d1fd 100644
--- a/server/lib/activitypub/url.ts
+++ b/server/lib/activitypub/url.ts
@@ -1,102 +1,102 @@
1import { WEBSERVER } from '../../initializers/constants' 1import { WEBSERVER } from '../../initializers/constants'
2import { 2import {
3 MAbuseId,
3 MActor, 4 MActor,
4 MActorFollowActors, 5 MActorFollowActors,
5 MActorId, 6 MActorId,
6 MActorUrl, 7 MActorUrl,
7 MCommentId, 8 MCommentId,
8 MVideoId, 9 MVideoId,
10 MVideoPlaylistElement,
9 MVideoUrl, 11 MVideoUrl,
10 MVideoUUID, 12 MVideoUUID
11 MAbuseId,
12 MVideoPlaylistElement
13} from '../../types/models' 13} from '../../types/models'
14import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist'
15import { MVideoFileVideoUUID } from '../../types/models/video/video-file' 14import { MVideoFileVideoUUID } from '../../types/models/video/video-file'
15import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist'
16import { MStreamingPlaylist } from '../../types/models/video/video-streaming-playlist' 16import { MStreamingPlaylist } from '../../types/models/video/video-streaming-playlist'
17 17
18function getVideoActivityPubUrl (video: MVideoUUID) { 18function getLocalVideoActivityPubUrl (video: MVideoUUID) {
19 return WEBSERVER.URL + '/videos/watch/' + video.uuid 19 return WEBSERVER.URL + '/videos/watch/' + video.uuid
20} 20}
21 21
22function getVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) { 22function getLocalVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) {
23 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid 23 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid
24} 24}
25 25
26function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, videoPlaylistElement: MVideoPlaylistElement) { 26function getLocalVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, videoPlaylistElement: MVideoPlaylistElement) {
27 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/videos/' + videoPlaylistElement.id 27 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/videos/' + videoPlaylistElement.id
28} 28}
29 29
30function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) { 30function getLocalVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) {
31 const suffixFPS = videoFile.fps && videoFile.fps !== -1 ? '-' + videoFile.fps : '' 31 const suffixFPS = videoFile.fps && videoFile.fps !== -1 ? '-' + videoFile.fps : ''
32 32
33 return `${WEBSERVER.URL}/redundancy/videos/${videoFile.Video.uuid}/${videoFile.resolution}${suffixFPS}` 33 return `${WEBSERVER.URL}/redundancy/videos/${videoFile.Video.uuid}/${videoFile.resolution}${suffixFPS}`
34} 34}
35 35
36function getVideoCacheStreamingPlaylistActivityPubUrl (video: MVideoUUID, playlist: MStreamingPlaylist) { 36function getLocalVideoCacheStreamingPlaylistActivityPubUrl (video: MVideoUUID, playlist: MStreamingPlaylist) {
37 return `${WEBSERVER.URL}/redundancy/streaming-playlists/${playlist.getStringType()}/${video.uuid}` 37 return `${WEBSERVER.URL}/redundancy/streaming-playlists/${playlist.getStringType()}/${video.uuid}`
38} 38}
39 39
40function getVideoCommentActivityPubUrl (video: MVideoUUID, videoComment: MCommentId) { 40function getLocalVideoCommentActivityPubUrl (video: MVideoUUID, videoComment: MCommentId) {
41 return WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id 41 return WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id
42} 42}
43 43
44function getVideoChannelActivityPubUrl (videoChannelName: string) { 44function getLocalVideoChannelActivityPubUrl (videoChannelName: string) {
45 return WEBSERVER.URL + '/video-channels/' + videoChannelName 45 return WEBSERVER.URL + '/video-channels/' + videoChannelName
46} 46}
47 47
48function getAccountActivityPubUrl (accountName: string) { 48function getLocalAccountActivityPubUrl (accountName: string) {
49 return WEBSERVER.URL + '/accounts/' + accountName 49 return WEBSERVER.URL + '/accounts/' + accountName
50} 50}
51 51
52function getAbuseActivityPubUrl (abuse: MAbuseId) { 52function getLocalAbuseActivityPubUrl (abuse: MAbuseId) {
53 return WEBSERVER.URL + '/admin/abuses/' + abuse.id 53 return WEBSERVER.URL + '/admin/abuses/' + abuse.id
54} 54}
55 55
56function getVideoViewActivityPubUrl (byActor: MActorUrl, video: MVideoId) { 56function getLocalVideoViewActivityPubUrl (byActor: MActorUrl, video: MVideoId) {
57 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() 57 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString()
58} 58}
59 59
60function getVideoLikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) { 60function getVideoLikeActivityPubUrlByLocalActor (byActor: MActorUrl, video: MVideoId) {
61 return byActor.url + '/likes/' + video.id 61 return byActor.url + '/likes/' + video.id
62} 62}
63 63
64function getVideoDislikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) { 64function getVideoDislikeActivityPubUrlByLocalActor (byActor: MActorUrl, video: MVideoId) {
65 return byActor.url + '/dislikes/' + video.id 65 return byActor.url + '/dislikes/' + video.id
66} 66}
67 67
68function getVideoSharesActivityPubUrl (video: MVideoUrl) { 68function getLocalVideoSharesActivityPubUrl (video: MVideoUrl) {
69 return video.url + '/announces' 69 return video.url + '/announces'
70} 70}
71 71
72function getVideoCommentsActivityPubUrl (video: MVideoUrl) { 72function getLocalVideoCommentsActivityPubUrl (video: MVideoUrl) {
73 return video.url + '/comments' 73 return video.url + '/comments'
74} 74}
75 75
76function getVideoLikesActivityPubUrl (video: MVideoUrl) { 76function getLocalVideoLikesActivityPubUrl (video: MVideoUrl) {
77 return video.url + '/likes' 77 return video.url + '/likes'
78} 78}
79 79
80function getVideoDislikesActivityPubUrl (video: MVideoUrl) { 80function getLocalVideoDislikesActivityPubUrl (video: MVideoUrl) {
81 return video.url + '/dislikes' 81 return video.url + '/dislikes'
82} 82}
83 83
84function getActorFollowActivityPubUrl (follower: MActor, following: MActorId) { 84function getLocalActorFollowActivityPubUrl (follower: MActor, following: MActorId) {
85 return follower.url + '/follows/' + following.id 85 return follower.url + '/follows/' + following.id
86} 86}
87 87
88function getActorFollowAcceptActivityPubUrl (actorFollow: MActorFollowActors) { 88function getLocalActorFollowAcceptActivityPubUrl (actorFollow: MActorFollowActors) {
89 const follower = actorFollow.ActorFollower 89 const follower = actorFollow.ActorFollower
90 const me = actorFollow.ActorFollowing 90 const me = actorFollow.ActorFollowing
91 91
92 return follower.url + '/accepts/follows/' + me.id 92 return WEBSERVER.URL + '/accepts/follows/' + follower.id + '/' + me.id
93} 93}
94 94
95function getActorFollowRejectActivityPubUrl (follower: MActorUrl, following: MActorId) { 95function getLocalActorFollowRejectActivityPubUrl (follower: MActorId, following: MActorId) {
96 return follower.url + '/rejects/follows/' + following.id 96 return WEBSERVER.URL + '/rejects/follows/' + follower.id + '/' + following.id
97} 97}
98 98
99function getVideoAnnounceActivityPubUrl (byActor: MActorId, video: MVideoUrl) { 99function getLocalVideoAnnounceActivityPubUrl (byActor: MActorId, video: MVideoUrl) {
100 return video.url + '/announces/' + byActor.id 100 return video.url + '/announces/' + byActor.id
101} 101}
102 102
@@ -113,27 +113,28 @@ function getUndoActivityPubUrl (originalUrl: string) {
113} 113}
114 114
115export { 115export {
116 getVideoActivityPubUrl, 116 getLocalVideoActivityPubUrl,
117 getVideoPlaylistElementActivityPubUrl, 117 getLocalVideoPlaylistActivityPubUrl,
118 getVideoPlaylistActivityPubUrl, 118 getLocalVideoPlaylistElementActivityPubUrl,
119 getVideoCacheStreamingPlaylistActivityPubUrl, 119 getLocalVideoCacheFileActivityPubUrl,
120 getVideoChannelActivityPubUrl, 120 getLocalVideoCacheStreamingPlaylistActivityPubUrl,
121 getAccountActivityPubUrl, 121 getLocalVideoCommentActivityPubUrl,
122 getAbuseActivityPubUrl, 122 getLocalVideoChannelActivityPubUrl,
123 getActorFollowActivityPubUrl, 123 getLocalAccountActivityPubUrl,
124 getActorFollowAcceptActivityPubUrl, 124 getLocalAbuseActivityPubUrl,
125 getVideoAnnounceActivityPubUrl, 125 getLocalActorFollowActivityPubUrl,
126 getLocalActorFollowAcceptActivityPubUrl,
127 getLocalVideoAnnounceActivityPubUrl,
126 getUpdateActivityPubUrl, 128 getUpdateActivityPubUrl,
127 getUndoActivityPubUrl, 129 getUndoActivityPubUrl,
128 getVideoViewActivityPubUrl, 130 getVideoLikeActivityPubUrlByLocalActor,
129 getVideoLikeActivityPubUrl, 131 getLocalVideoViewActivityPubUrl,
130 getVideoDislikeActivityPubUrl, 132 getVideoDislikeActivityPubUrlByLocalActor,
131 getActorFollowRejectActivityPubUrl, 133 getLocalActorFollowRejectActivityPubUrl,
132 getVideoCommentActivityPubUrl,
133 getDeleteActivityPubUrl, 134 getDeleteActivityPubUrl,
134 getVideoSharesActivityPubUrl, 135 getLocalVideoSharesActivityPubUrl,
135 getVideoCommentsActivityPubUrl, 136 getLocalVideoCommentsActivityPubUrl,
136 getVideoLikesActivityPubUrl, 137 getLocalVideoLikesActivityPubUrl,
137 getVideoDislikesActivityPubUrl, 138 getLocalVideoDislikesActivityPubUrl,
138 getVideoCacheFileActivityPubUrl 139
139} 140}
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts
index e09e5d9ec..581a2bca1 100644
--- a/server/lib/activitypub/video-rates.ts
+++ b/server/lib/activitypub/video-rates.ts
@@ -8,7 +8,7 @@ import { logger } from '../../helpers/logger'
8import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 8import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
9import { doRequest } from '../../helpers/requests' 9import { doRequest } from '../../helpers/requests'
10import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 10import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
11import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from './url' 11import { getVideoDislikeActivityPubUrlByLocalActor, getVideoLikeActivityPubUrlByLocalActor } from './url'
12import { sendDislike } from './send/send-dislike' 12import { sendDislike } from './send/send-dislike'
13import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../types/models' 13import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../types/models'
14 14
@@ -82,14 +82,14 @@ async function sendVideoRateChange (
82 if (dislikes > 0) await sendDislike(actor, video, t) 82 if (dislikes > 0) await sendDislike(actor, video, t)
83} 83}
84 84
85function getRateUrl (rateType: VideoRateType, actor: MActorUrl, video: MVideoId) { 85function getLocalRateUrl (rateType: VideoRateType, actor: MActorUrl, video: MVideoId) {
86 return rateType === 'like' 86 return rateType === 'like'
87 ? getVideoLikeActivityPubUrl(actor, video) 87 ? getVideoLikeActivityPubUrlByLocalActor(actor, video)
88 : getVideoDislikeActivityPubUrl(actor, video) 88 : getVideoDislikeActivityPubUrlByLocalActor(actor, video)
89} 89}
90 90
91export { 91export {
92 getRateUrl, 92 getLocalRateUrl,
93 createRates, 93 createRates,
94 sendVideoRateChange 94 sendVideoRateChange
95} 95}
diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts
index 7a4f85f8b..82c95be80 100644
--- a/server/lib/job-queue/handlers/activitypub-follow.ts
+++ b/server/lib/job-queue/handlers/activitypub-follow.ts
@@ -12,6 +12,7 @@ import { Notifier } from '../../notifier'
12import { sequelizeTypescript } from '../../../initializers/database' 12import { sequelizeTypescript } from '../../../initializers/database'
13import { MActor, MActorFollowActors, MActorFull } from '../../../types/models' 13import { MActor, MActorFollowActors, MActorFull } from '../../../types/models'
14import { ActivitypubFollowPayload } from '@shared/models' 14import { ActivitypubFollowPayload } from '@shared/models'
15import { getLocalActorFollowActivityPubUrl } from '@server/lib/activitypub/url'
15 16
16async function processActivityPubFollow (job: Bull.Job) { 17async function processActivityPubFollow (job: Bull.Job) {
17 const payload = job.data as ActivitypubFollowPayload 18 const payload = job.data as ActivitypubFollowPayload
@@ -61,6 +62,7 @@ async function follow (fromActor: MActor, targetActor: MActorFull, isAutoFollow
61 }, 62 },
62 defaults: { 63 defaults: {
63 state, 64 state,
65 url: getLocalActorFollowActivityPubUrl(fromActor, targetActor),
64 actorId: fromActor.id, 66 actorId: fromActor.id,
65 targetActorId: targetActor.id 67 targetActorId: targetActor.id
66 }, 68 },
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts
index 54d9a9894..82005a2c8 100644
--- a/server/lib/schedulers/videos-redundancy-scheduler.ts
+++ b/server/lib/schedulers/videos-redundancy-scheduler.ts
@@ -1,19 +1,10 @@
1import { AbstractScheduler } from './abstract-scheduler'
2import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants'
3import { logger } from '../../helpers/logger'
4import { VideosRedundancyStrategy } from '../../../shared/models/redundancy'
5import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
6import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent'
7import { join } from 'path'
8import { move } from 'fs-extra' 1import { move } from 'fs-extra'
9import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' 2import { join } from 'path'
10import { getVideoCacheFileActivityPubUrl, getVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' 3import { getServerActor } from '@server/models/application/application'
11import { removeVideoRedundancy } from '../redundancy' 4import { VideoModel } from '@server/models/video/video'
12import { getOrCreateVideoAndAccountAndChannel } from '../activitypub/videos'
13import { downloadPlaylistSegments } from '../hls'
14import { CONFIG } from '../../initializers/config'
15import { 5import {
16 MStreamingPlaylist, MStreamingPlaylistFiles, 6 MStreamingPlaylist,
7 MStreamingPlaylistFiles,
17 MStreamingPlaylistVideo, 8 MStreamingPlaylistVideo,
18 MVideoAccountLight, 9 MVideoAccountLight,
19 MVideoFile, 10 MVideoFile,
@@ -23,9 +14,19 @@ import {
23 MVideoRedundancyVideo, 14 MVideoRedundancyVideo,
24 MVideoWithAllFiles 15 MVideoWithAllFiles
25} from '@server/types/models' 16} from '@server/types/models'
17import { VideosRedundancyStrategy } from '../../../shared/models/redundancy'
18import { logger } from '../../helpers/logger'
19import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent'
20import { CONFIG } from '../../initializers/config'
21import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants'
22import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
23import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send'
24import { getLocalVideoCacheFileActivityPubUrl, getLocalVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url'
25import { getOrCreateVideoAndAccountAndChannel } from '../activitypub/videos'
26import { downloadPlaylistSegments } from '../hls'
27import { removeVideoRedundancy } from '../redundancy'
26import { getVideoFilename } from '../video-paths' 28import { getVideoFilename } from '../video-paths'
27import { VideoModel } from '@server/models/video/video' 29import { AbstractScheduler } from './abstract-scheduler'
28import { getServerActor } from '@server/models/application/application'
29 30
30type CandidateToDuplicate = { 31type CandidateToDuplicate = {
31 redundancy: VideosRedundancyStrategy 32 redundancy: VideosRedundancyStrategy
@@ -230,7 +231,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler {
230 231
231 const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ 232 const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({
232 expiresOn, 233 expiresOn,
233 url: getVideoCacheFileActivityPubUrl(file), 234 url: getLocalVideoCacheFileActivityPubUrl(file),
234 fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), 235 fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL),
235 strategy, 236 strategy,
236 videoFileId: file.id, 237 videoFileId: file.id,
@@ -269,7 +270,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler {
269 270
270 const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ 271 const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({
271 expiresOn, 272 expiresOn,
272 url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), 273 url: getLocalVideoCacheStreamingPlaylistActivityPubUrl(video, playlist),
273 fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), 274 fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL),
274 strategy, 275 strategy,
275 videoStreamingPlaylistId: playlist.id, 276 videoStreamingPlaylistId: playlist.id,
diff --git a/server/lib/user.ts b/server/lib/user.ts
index 7d6497302..6b0fd9b88 100644
--- a/server/lib/user.ts
+++ b/server/lib/user.ts
@@ -11,7 +11,7 @@ import { ActorModel } from '../models/activitypub/actor'
11import { MAccountDefault, MActorDefault, MChannelActor } from '../types/models' 11import { MAccountDefault, MActorDefault, MChannelActor } from '../types/models'
12import { MUser, MUserDefault, MUserId } from '../types/models/user' 12import { MUser, MUserDefault, MUserId } from '../types/models/user'
13import { buildActorInstance, setAsyncActorKeys } from './activitypub/actor' 13import { buildActorInstance, setAsyncActorKeys } from './activitypub/actor'
14import { getAccountActivityPubUrl } from './activitypub/url' 14import { getLocalAccountActivityPubUrl } from './activitypub/url'
15import { Emailer } from './emailer' 15import { Emailer } from './emailer'
16import { LiveManager } from './live-manager' 16import { LiveManager } from './live-manager'
17import { Redis } from './redis' 17import { Redis } from './redis'
@@ -74,7 +74,7 @@ async function createLocalAccountWithoutKeys (parameters: {
74 type?: ActivityPubActorType 74 type?: ActivityPubActorType
75}) { 75}) {
76 const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters 76 const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters
77 const url = getAccountActivityPubUrl(name) 77 const url = getLocalAccountActivityPubUrl(name)
78 78
79 const actorInstance = buildActorInstance(type, url, name) 79 const actorInstance = buildActorInstance(type, url, name)
80 const actorInstanceCreated: MActorDefault = await actorInstance.save({ transaction: t }) 80 const actorInstanceCreated: MActorDefault = await actorInstance.save({ transaction: t })
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts
index 8928dda12..49bdf4869 100644
--- a/server/lib/video-channel.ts
+++ b/server/lib/video-channel.ts
@@ -1,11 +1,11 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { v4 as uuidv4 } from 'uuid' 2import { v4 as uuidv4 } from 'uuid'
3import { VideoChannelCreate } from '../../shared/models' 3import { VideoChannelCreate } from '../../shared/models'
4import { VideoChannelModel } from '../models/video/video-channel'
5import { buildActorInstance } from './activitypub/actor'
6import { VideoModel } from '../models/video/video' 4import { VideoModel } from '../models/video/video'
5import { VideoChannelModel } from '../models/video/video-channel'
7import { MAccountId, MChannelDefault, MChannelId } from '../types/models' 6import { MAccountId, MChannelDefault, MChannelId } from '../types/models'
8import { getVideoChannelActivityPubUrl } from './activitypub/url' 7import { buildActorInstance } from './activitypub/actor'
8import { getLocalVideoChannelActivityPubUrl } from './activitypub/url'
9import { federateVideoIfNeeded } from './activitypub/videos' 9import { federateVideoIfNeeded } from './activitypub/videos'
10 10
11type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T } 11type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T }
@@ -16,7 +16,7 @@ async function createLocalVideoChannel <T extends MAccountId> (
16 t: Sequelize.Transaction 16 t: Sequelize.Transaction
17): Promise<CustomVideoChannelModelAccount<T>> { 17): Promise<CustomVideoChannelModelAccount<T>> {
18 const uuid = uuidv4() 18 const uuid = uuidv4()
19 const url = getVideoChannelActivityPubUrl(videoChannelInfo.name) 19 const url = getLocalVideoChannelActivityPubUrl(videoChannelInfo.name)
20 const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid) 20 const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid)
21 21
22 const actorInstanceCreated = await actorInstance.save({ transaction: t }) 22 const actorInstanceCreated = await actorInstance.save({ transaction: t })
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts
index c92a7c43a..736ebb2f8 100644
--- a/server/lib/video-comment.ts
+++ b/server/lib/video-comment.ts
@@ -5,9 +5,9 @@ import { sequelizeTypescript } from '@server/initializers/database'
5import { ResultList } from '../../shared/models' 5import { ResultList } from '../../shared/models'
6import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model' 6import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model'
7import { VideoCommentModel } from '../models/video/video-comment' 7import { VideoCommentModel } from '../models/video/video-comment'
8import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight, MCommentOwnerVideo } from '../types/models' 8import { MAccountDefault, MComment, MCommentOwnerVideo, MCommentOwnerVideoReply, MVideoFullLight } from '../types/models'
9import { sendCreateVideoComment, sendDeleteVideoComment } from './activitypub/send' 9import { sendCreateVideoComment, sendDeleteVideoComment } from './activitypub/send'
10import { getVideoCommentActivityPubUrl } from './activitypub/url' 10import { getLocalVideoCommentActivityPubUrl } from './activitypub/url'
11import { Hooks } from './plugins/hooks' 11import { Hooks } from './plugins/hooks'
12 12
13async function removeComment (videoCommentInstance: MCommentOwnerVideo) { 13async function removeComment (videoCommentInstance: MCommentOwnerVideo) {
@@ -51,7 +51,7 @@ async function createVideoComment (obj: {
51 url: new Date().toISOString() 51 url: new Date().toISOString()
52 }, { transaction: t, validate: false }) 52 }, { transaction: t, validate: false })
53 53
54 comment.url = getVideoCommentActivityPubUrl(obj.video, comment) 54 comment.url = getLocalVideoCommentActivityPubUrl(obj.video, comment)
55 55
56 const savedComment: MCommentOwnerVideoReply = await comment.save({ transaction: t }) 56 const savedComment: MCommentOwnerVideoReply = await comment.save({ transaction: t })
57 savedComment.InReplyToVideoComment = obj.inReplyToComment 57 savedComment.InReplyToVideoComment = obj.inReplyToComment
diff --git a/server/lib/video-playlist.ts b/server/lib/video-playlist.ts
index 6eeb70c8e..a1af2e1af 100644
--- a/server/lib/video-playlist.ts
+++ b/server/lib/video-playlist.ts
@@ -1,10 +1,10 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { VideoPlaylistModel } from '../models/video/video-playlist'
3import { VideoPlaylistPrivacy } from '../../shared/models/videos/playlist/video-playlist-privacy.model' 2import { VideoPlaylistPrivacy } from '../../shared/models/videos/playlist/video-playlist-privacy.model'
4import { getVideoPlaylistActivityPubUrl } from './activitypub/url'
5import { VideoPlaylistType } from '../../shared/models/videos/playlist/video-playlist-type.model' 3import { VideoPlaylistType } from '../../shared/models/videos/playlist/video-playlist-type.model'
4import { VideoPlaylistModel } from '../models/video/video-playlist'
6import { MAccount } from '../types/models' 5import { MAccount } from '../types/models'
7import { MVideoPlaylistOwner } from '../types/models/video/video-playlist' 6import { MVideoPlaylistOwner } from '../types/models/video/video-playlist'
7import { getLocalVideoPlaylistActivityPubUrl } from './activitypub/url'
8 8
9async function createWatchLaterPlaylist (account: MAccount, t: Sequelize.Transaction) { 9async function createWatchLaterPlaylist (account: MAccount, t: Sequelize.Transaction) {
10 const videoPlaylist: MVideoPlaylistOwner = new VideoPlaylistModel({ 10 const videoPlaylist: MVideoPlaylistOwner = new VideoPlaylistModel({
@@ -14,7 +14,7 @@ async function createWatchLaterPlaylist (account: MAccount, t: Sequelize.Transac
14 ownerAccountId: account.id 14 ownerAccountId: account.id
15 }) 15 })
16 16
17 videoPlaylist.url = getVideoPlaylistActivityPubUrl(videoPlaylist) // We use the UUID, so set the URL after building the object 17 videoPlaylist.url = getLocalVideoPlaylistActivityPubUrl(videoPlaylist) // We use the UUID, so set the URL after building the object
18 18
19 await videoPlaylist.save({ transaction: t }) 19 await videoPlaylist.save({ transaction: t })
20 20
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts
index cbc144f69..15a8c7983 100644
--- a/server/middlewares/validators/videos/video-rates.ts
+++ b/server/middlewares/validators/videos/video-rates.ts
@@ -38,7 +38,6 @@ const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) {
38 if (!rate) { 38 if (!rate) {
39 return res.status(404) 39 return res.status(404)
40 .json({ error: 'Video rate not found' }) 40 .json({ error: 'Video rate not found' })
41 .end()
42 } 41 }
43 42
44 res.locals.accountVideoRate = rate 43 res.locals.accountVideoRate = rate
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts
index 5064987dc..6955f45ee 100644
--- a/server/models/account/account-video-rate.ts
+++ b/server/models/account/account-video-rate.ts
@@ -168,7 +168,8 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
168 model: ActorModel.unscoped(), 168 model: ActorModel.unscoped(),
169 required: true, 169 required: true,
170 where: { 170 where: {
171 preferredUsername: accountName 171 preferredUsername: accountName,
172 serverId: null
172 } 173 }
173 } 174 }
174 ] 175 ]
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 10c13304f..58bc63d34 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -1,5 +1,6 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { difference, values } from 'lodash' 2import { difference, values } from 'lodash'
3import { IncludeOptions, Op, QueryTypes, Transaction, WhereOptions } from 'sequelize'
3import { 4import {
4 AfterCreate, 5 AfterCreate,
5 AfterDestroy, 6 AfterDestroy,
@@ -11,22 +12,16 @@ import {
11 DataType, 12 DataType,
12 Default, 13 Default,
13 ForeignKey, 14 ForeignKey,
15 Is,
14 IsInt, 16 IsInt,
15 Max, 17 Max,
16 Model, 18 Model,
17 Table, 19 Table,
18 UpdatedAt 20 UpdatedAt
19} from 'sequelize-typescript' 21} from 'sequelize-typescript'
20import { FollowState } from '../../../shared/models/actors' 22import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
21import { ActorFollow } from '../../../shared/models/actors/follow.model' 23import { getServerActor } from '@server/models/application/application'
22import { logger } from '../../helpers/logger' 24import { VideoModel } from '@server/models/video/video'
23import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants'
24import { ServerModel } from '../server/server'
25import { createSafeIn, getFollowsSort, getSort, searchAttribute } from '../utils'
26import { ActorModel, unusedActorAttributesForAPI } from './actor'
27import { VideoChannelModel } from '../video/video-channel'
28import { AccountModel } from '../account/account'
29import { IncludeOptions, Op, QueryTypes, Transaction, WhereOptions } from 'sequelize'
30import { 25import {
31 MActorFollowActorsDefault, 26 MActorFollowActorsDefault,
32 MActorFollowActorsDefaultSubscription, 27 MActorFollowActorsDefaultSubscription,
@@ -35,8 +30,15 @@ import {
35 MActorFollowSubscriptions 30 MActorFollowSubscriptions
36} from '@server/types/models' 31} from '@server/types/models'
37import { ActivityPubActorType } from '@shared/models' 32import { ActivityPubActorType } from '@shared/models'
38import { VideoModel } from '@server/models/video/video' 33import { FollowState } from '../../../shared/models/actors'
39import { getServerActor } from '@server/models/application/application' 34import { ActorFollow } from '../../../shared/models/actors/follow.model'
35import { logger } from '../../helpers/logger'
36import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants'
37import { AccountModel } from '../account/account'
38import { ServerModel } from '../server/server'
39import { createSafeIn, getFollowsSort, getSort, searchAttribute, throwIfNotValid } from '../utils'
40import { VideoChannelModel } from '../video/video-channel'
41import { ActorModel, unusedActorAttributesForAPI } from './actor'
40 42
41@Table({ 43@Table({
42 tableName: 'actorFollow', 44 tableName: 'actorFollow',
@@ -53,6 +55,10 @@ import { getServerActor } from '@server/models/application/application'
53 }, 55 },
54 { 56 {
55 fields: [ 'score' ] 57 fields: [ 'score' ]
58 },
59 {
60 fields: [ 'url' ],
61 unique: true
56 } 62 }
57 ] 63 ]
58}) 64})
@@ -69,6 +75,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
69 @Column 75 @Column
70 score: number 76 score: number
71 77
78 // Allow null because we added this column in PeerTube v3, and don't want to generate fake URLs of remote follows
79 @AllowNull(true)
80 @Is('ActorFollowUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
81 @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max))
82 url: string
83
72 @CreatedAt 84 @CreatedAt
73 createdAt: Date 85 createdAt: Date
74 86
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts
index d4b213686..b1adbcb86 100644
--- a/server/models/video/video-format-utils.ts
+++ b/server/models/video/video-format-utils.ts
@@ -4,10 +4,10 @@ import { ActivityTagObject, ActivityUrlObject, VideoObject } from '../../../shar
4import { MIMETYPES, WEBSERVER } from '../../initializers/constants' 4import { MIMETYPES, WEBSERVER } from '../../initializers/constants'
5import { VideoCaptionModel } from './video-caption' 5import { VideoCaptionModel } from './video-caption'
6import { 6import {
7 getVideoCommentsActivityPubUrl, 7 getLocalVideoCommentsActivityPubUrl,
8 getVideoDislikesActivityPubUrl, 8 getLocalVideoDislikesActivityPubUrl,
9 getVideoLikesActivityPubUrl, 9 getLocalVideoLikesActivityPubUrl,
10 getVideoSharesActivityPubUrl 10 getLocalVideoSharesActivityPubUrl
11} from '../../lib/activitypub/url' 11} from '../../lib/activitypub/url'
12import { isArray } from '../../helpers/custom-validators/misc' 12import { isArray } from '../../helpers/custom-validators/misc'
13import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model' 13import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model'
@@ -382,10 +382,10 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject {
382 height: i.height 382 height: i.height
383 })), 383 })),
384 url, 384 url,
385 likes: getVideoLikesActivityPubUrl(video), 385 likes: getLocalVideoLikesActivityPubUrl(video),
386 dislikes: getVideoDislikesActivityPubUrl(video), 386 dislikes: getLocalVideoDislikesActivityPubUrl(video),
387 shares: getVideoSharesActivityPubUrl(video), 387 shares: getLocalVideoSharesActivityPubUrl(video),
388 comments: getVideoCommentsActivityPubUrl(video), 388 comments: getLocalVideoCommentsActivityPubUrl(video),
389 attributedTo: [ 389 attributedTo: [
390 { 390 {
391 type: 'Person', 391 type: 'Person',
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts
index cee85cc4b..73c212a32 100644
--- a/server/tests/api/server/follows-moderation.ts
+++ b/server/tests/api/server/follows-moderation.ts
@@ -81,6 +81,8 @@ describe('Test follows moderation', function () {
81 }) 81 })
82 82
83 it('Should remove follower on server 2', async function () { 83 it('Should remove follower on server 2', async function () {
84 this.timeout(10000)
85
84 await removeFollower(servers[1].url, servers[1].accessToken, servers[0]) 86 await removeFollower(servers[1].url, servers[1].accessToken, servers[0])
85 87
86 await waitJobs(servers) 88 await waitJobs(servers)
@@ -91,6 +93,8 @@ describe('Test follows moderation', function () {
91 }) 93 })
92 94
93 it('Should disable followers on server 2', async function () { 95 it('Should disable followers on server 2', async function () {
96 this.timeout(10000)
97
94 const subConfig = { 98 const subConfig = {
95 followers: { 99 followers: {
96 instance: { 100 instance: {
@@ -109,6 +113,8 @@ describe('Test follows moderation', function () {
109 }) 113 })
110 114
111 it('Should re enable followers on server 2', async function () { 115 it('Should re enable followers on server 2', async function () {
116 this.timeout(10000)
117
112 const subConfig = { 118 const subConfig = {
113 followers: { 119 followers: {
114 instance: { 120 instance: {
@@ -151,6 +157,8 @@ describe('Test follows moderation', function () {
151 }) 157 })
152 158
153 it('Should accept a follower', async function () { 159 it('Should accept a follower', async function () {
160 this.timeout(10000)
161
154 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port) 162 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port)
155 await waitJobs(servers) 163 await waitJobs(servers)
156 164