diff options
Diffstat (limited to 'server/lib')
-rw-r--r-- | server/lib/activitypub/activity.ts | 14 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/get.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 58 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-dislike.ts | 11 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-flag.ts | 8 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-undo.ts | 43 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 36 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-create.ts | 23 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-undo.ts | 19 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-update.ts | 9 | ||||
-rw-r--r-- | server/lib/activitypub/videos/get.ts | 8 |
11 files changed, 141 insertions, 92 deletions
diff --git a/server/lib/activitypub/activity.ts b/server/lib/activitypub/activity.ts index 1f6ec221e..0fed3e8fd 100644 --- a/server/lib/activitypub/activity.ts +++ b/server/lib/activitypub/activity.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { ActivityType } from '@shared/models' | 1 | import { doJSONRequest } from '@server/helpers/requests' |
2 | import { APObjectId, ActivityObject, ActivityPubActor, ActivityType } from '@shared/models' | ||
2 | 3 | ||
3 | function getAPId (object: string | { id: string }) { | 4 | function getAPId (object: string | { id: string }) { |
4 | if (typeof object === 'string') return object | 5 | if (typeof object === 'string') return object |
@@ -32,8 +33,19 @@ function buildAvailableActivities (): ActivityType[] { | |||
32 | ] | 33 | ] |
33 | } | 34 | } |
34 | 35 | ||
36 | async function fetchAPObject <T extends (ActivityObject | ActivityPubActor)> (object: APObjectId) { | ||
37 | if (typeof object === 'string') { | ||
38 | const { body } = await doJSONRequest<Exclude<T, string>>(object, { activityPub: true }) | ||
39 | |||
40 | return body | ||
41 | } | ||
42 | |||
43 | return object as Exclude<T, string> | ||
44 | } | ||
45 | |||
35 | export { | 46 | export { |
36 | getAPId, | 47 | getAPId, |
48 | fetchAPObject, | ||
37 | getActivityStreamDuration, | 49 | getActivityStreamDuration, |
38 | buildAvailableActivities, | 50 | buildAvailableActivities, |
39 | getDurationFromActivityStream | 51 | getDurationFromActivityStream |
diff --git a/server/lib/activitypub/playlists/get.ts b/server/lib/activitypub/playlists/get.ts index bfaf52cc9..c34554d69 100644 --- a/server/lib/activitypub/playlists/get.ts +++ b/server/lib/activitypub/playlists/get.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | 1 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' |
2 | import { MVideoPlaylistFullSummary } from '@server/types/models' | 2 | import { MVideoPlaylistFullSummary } from '@server/types/models' |
3 | import { APObject } from '@shared/models' | 3 | import { APObjectId } from '@shared/models' |
4 | import { getAPId } from '../activity' | 4 | import { getAPId } from '../activity' |
5 | import { createOrUpdateVideoPlaylist } from './create-update' | 5 | import { createOrUpdateVideoPlaylist } from './create-update' |
6 | import { scheduleRefreshIfNeeded } from './refresh' | 6 | import { scheduleRefreshIfNeeded } from './refresh' |
7 | import { fetchRemoteVideoPlaylist } from './shared' | 7 | import { fetchRemoteVideoPlaylist } from './shared' |
8 | 8 | ||
9 | async function getOrCreateAPVideoPlaylist (playlistObjectArg: APObject): Promise<MVideoPlaylistFullSummary> { | 9 | async function getOrCreateAPVideoPlaylist (playlistObjectArg: APObjectId): Promise<MVideoPlaylistFullSummary> { |
10 | const playlistUrl = getAPId(playlistObjectArg) | 10 | const playlistUrl = getAPId(playlistObjectArg) |
11 | 11 | ||
12 | const playlistFromDatabase = await VideoPlaylistModel.loadByUrlWithAccountAndChannelSummary(playlistUrl) | 12 | const playlistFromDatabase = await VideoPlaylistModel.loadByUrlWithAccountAndChannelSummary(playlistUrl) |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 1e6e8956c..e89d1ab45 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -1,13 +1,24 @@ | |||
1 | import { isBlockedByServerOrAccount } from '@server/lib/blocklist' | 1 | import { isBlockedByServerOrAccount } from '@server/lib/blocklist' |
2 | import { isRedundancyAccepted } from '@server/lib/redundancy' | 2 | import { isRedundancyAccepted } from '@server/lib/redundancy' |
3 | import { VideoModel } from '@server/models/video/video' | 3 | import { VideoModel } from '@server/models/video/video' |
4 | import { ActivityCreate, CacheFileObject, PlaylistObject, VideoCommentObject, VideoObject, WatchActionObject } from '@shared/models' | 4 | import { |
5 | AbuseObject, | ||
6 | ActivityCreate, | ||
7 | ActivityCreateObject, | ||
8 | ActivityObject, | ||
9 | CacheFileObject, | ||
10 | PlaylistObject, | ||
11 | VideoCommentObject, | ||
12 | VideoObject, | ||
13 | WatchActionObject | ||
14 | } from '@shared/models' | ||
5 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 15 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
6 | import { logger } from '../../../helpers/logger' | 16 | import { logger } from '../../../helpers/logger' |
7 | import { sequelizeTypescript } from '../../../initializers/database' | 17 | import { sequelizeTypescript } from '../../../initializers/database' |
8 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' | 18 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' |
9 | import { MActorSignature, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../../types/models' | 19 | import { MActorSignature, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../../types/models' |
10 | import { Notifier } from '../../notifier' | 20 | import { Notifier } from '../../notifier' |
21 | import { fetchAPObject } from '../activity' | ||
11 | import { createOrUpdateCacheFile } from '../cache-file' | 22 | import { createOrUpdateCacheFile } from '../cache-file' |
12 | import { createOrUpdateLocalVideoViewer } from '../local-video-viewer' | 23 | import { createOrUpdateLocalVideoViewer } from '../local-video-viewer' |
13 | import { createOrUpdateVideoPlaylist } from '../playlists' | 24 | import { createOrUpdateVideoPlaylist } from '../playlists' |
@@ -15,35 +26,35 @@ import { forwardVideoRelatedActivity } from '../send/shared/send-utils' | |||
15 | import { resolveThread } from '../video-comments' | 26 | import { resolveThread } from '../video-comments' |
16 | import { getOrCreateAPVideo } from '../videos' | 27 | import { getOrCreateAPVideo } from '../videos' |
17 | 28 | ||
18 | async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) { | 29 | async function processCreateActivity (options: APProcessorOptions<ActivityCreate<ActivityCreateObject>>) { |
19 | const { activity, byActor } = options | 30 | const { activity, byActor } = options |
20 | 31 | ||
21 | // Only notify if it is not from a fetcher job | 32 | // Only notify if it is not from a fetcher job |
22 | const notify = options.fromFetch !== true | 33 | const notify = options.fromFetch !== true |
23 | const activityObject = activity.object | 34 | const activityObject = await fetchAPObject<Exclude<ActivityObject, AbuseObject>>(activity.object) |
24 | const activityType = activityObject.type | 35 | const activityType = activityObject.type |
25 | 36 | ||
26 | if (activityType === 'Video') { | 37 | if (activityType === 'Video') { |
27 | return processCreateVideo(activity, notify) | 38 | return processCreateVideo(activityObject, notify) |
28 | } | 39 | } |
29 | 40 | ||
30 | if (activityType === 'Note') { | 41 | if (activityType === 'Note') { |
31 | // Comments will be fetched from videos | 42 | // Comments will be fetched from videos |
32 | if (options.fromFetch) return | 43 | if (options.fromFetch) return |
33 | 44 | ||
34 | return retryTransactionWrapper(processCreateVideoComment, activity, byActor, notify) | 45 | return retryTransactionWrapper(processCreateVideoComment, activity, activityObject, byActor, notify) |
35 | } | 46 | } |
36 | 47 | ||
37 | if (activityType === 'WatchAction') { | 48 | if (activityType === 'WatchAction') { |
38 | return retryTransactionWrapper(processCreateWatchAction, activity) | 49 | return retryTransactionWrapper(processCreateWatchAction, activityObject) |
39 | } | 50 | } |
40 | 51 | ||
41 | if (activityType === 'CacheFile') { | 52 | if (activityType === 'CacheFile') { |
42 | return retryTransactionWrapper(processCreateCacheFile, activity, byActor) | 53 | return retryTransactionWrapper(processCreateCacheFile, activity, activityObject, byActor) |
43 | } | 54 | } |
44 | 55 | ||
45 | if (activityType === 'Playlist') { | 56 | if (activityType === 'Playlist') { |
46 | return retryTransactionWrapper(processCreatePlaylist, activity, byActor) | 57 | return retryTransactionWrapper(processCreatePlaylist, activity, activityObject, byActor) |
47 | } | 58 | } |
48 | 59 | ||
49 | logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id }) | 60 | logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id }) |
@@ -58,9 +69,7 @@ export { | |||
58 | 69 | ||
59 | // --------------------------------------------------------------------------- | 70 | // --------------------------------------------------------------------------- |
60 | 71 | ||
61 | async function processCreateVideo (activity: ActivityCreate, notify: boolean) { | 72 | async function processCreateVideo (videoToCreateData: VideoObject, notify: boolean) { |
62 | const videoToCreateData = activity.object as VideoObject | ||
63 | |||
64 | const syncParam = { rates: false, shares: false, comments: false, thumbnail: true, refreshVideo: false } | 73 | const syncParam = { rates: false, shares: false, comments: false, thumbnail: true, refreshVideo: false } |
65 | const { video, created } = await getOrCreateAPVideo({ videoObject: videoToCreateData, syncParam }) | 74 | const { video, created } = await getOrCreateAPVideo({ videoObject: videoToCreateData, syncParam }) |
66 | 75 | ||
@@ -69,11 +78,13 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) { | |||
69 | return video | 78 | return video |
70 | } | 79 | } |
71 | 80 | ||
72 | async function processCreateCacheFile (activity: ActivityCreate, byActor: MActorSignature) { | 81 | async function processCreateCacheFile ( |
82 | activity: ActivityCreate<CacheFileObject | string>, | ||
83 | cacheFile: CacheFileObject, | ||
84 | byActor: MActorSignature | ||
85 | ) { | ||
73 | if (await isRedundancyAccepted(activity, byActor) !== true) return | 86 | if (await isRedundancyAccepted(activity, byActor) !== true) return |
74 | 87 | ||
75 | const cacheFile = activity.object as CacheFileObject | ||
76 | |||
77 | const { video } = await getOrCreateAPVideo({ videoObject: cacheFile.object }) | 88 | const { video } = await getOrCreateAPVideo({ videoObject: cacheFile.object }) |
78 | 89 | ||
79 | await sequelizeTypescript.transaction(async t => { | 90 | await sequelizeTypescript.transaction(async t => { |
@@ -87,9 +98,7 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: MActor | |||
87 | } | 98 | } |
88 | } | 99 | } |
89 | 100 | ||
90 | async function processCreateWatchAction (activity: ActivityCreate) { | 101 | async function processCreateWatchAction (watchAction: WatchActionObject) { |
91 | const watchAction = activity.object as WatchActionObject | ||
92 | |||
93 | if (watchAction.actionStatus !== 'CompletedActionStatus') return | 102 | if (watchAction.actionStatus !== 'CompletedActionStatus') return |
94 | 103 | ||
95 | const video = await VideoModel.loadByUrl(watchAction.object) | 104 | const video = await VideoModel.loadByUrl(watchAction.object) |
@@ -100,8 +109,12 @@ async function processCreateWatchAction (activity: ActivityCreate) { | |||
100 | }) | 109 | }) |
101 | } | 110 | } |
102 | 111 | ||
103 | async function processCreateVideoComment (activity: ActivityCreate, byActor: MActorSignature, notify: boolean) { | 112 | async function processCreateVideoComment ( |
104 | const commentObject = activity.object as VideoCommentObject | 113 | activity: ActivityCreate<VideoCommentObject | string>, |
114 | commentObject: VideoCommentObject, | ||
115 | byActor: MActorSignature, | ||
116 | notify: boolean | ||
117 | ) { | ||
105 | const byAccount = byActor.Account | 118 | const byAccount = byActor.Account |
106 | 119 | ||
107 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) | 120 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) |
@@ -144,8 +157,11 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: MAc | |||
144 | if (created && notify) Notifier.Instance.notifyOnNewComment(comment) | 157 | if (created && notify) Notifier.Instance.notifyOnNewComment(comment) |
145 | } | 158 | } |
146 | 159 | ||
147 | async function processCreatePlaylist (activity: ActivityCreate, byActor: MActorSignature) { | 160 | async function processCreatePlaylist ( |
148 | const playlistObject = activity.object as PlaylistObject | 161 | activity: ActivityCreate<PlaylistObject | string>, |
162 | playlistObject: PlaylistObject, | ||
163 | byActor: MActorSignature | ||
164 | ) { | ||
149 | const byAccount = byActor.Account | 165 | const byAccount = byActor.Account |
150 | 166 | ||
151 | if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url) | 167 | if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url) |
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index 44e349b22..4e270f917 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { VideoModel } from '@server/models/video/video' | 1 | import { VideoModel } from '@server/models/video/video' |
2 | import { ActivityCreate, ActivityDislike, DislikeObject } from '@shared/models' | 2 | import { ActivityDislike } from '@shared/models' |
3 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 3 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
4 | import { sequelizeTypescript } from '../../../initializers/database' | 4 | import { sequelizeTypescript } from '../../../initializers/database' |
5 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 5 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
@@ -7,7 +7,7 @@ import { APProcessorOptions } from '../../../types/activitypub-processor.model' | |||
7 | import { MActorSignature } from '../../../types/models' | 7 | import { MActorSignature } from '../../../types/models' |
8 | import { federateVideoIfNeeded, getOrCreateAPVideo } from '../videos' | 8 | import { federateVideoIfNeeded, getOrCreateAPVideo } from '../videos' |
9 | 9 | ||
10 | async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { | 10 | async function processDislikeActivity (options: APProcessorOptions<ActivityDislike>) { |
11 | const { activity, byActor } = options | 11 | const { activity, byActor } = options |
12 | return retryTransactionWrapper(processDislike, activity, byActor) | 12 | return retryTransactionWrapper(processDislike, activity, byActor) |
13 | } | 13 | } |
@@ -20,11 +20,8 @@ export { | |||
20 | 20 | ||
21 | // --------------------------------------------------------------------------- | 21 | // --------------------------------------------------------------------------- |
22 | 22 | ||
23 | async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) { | 23 | async function processDislike (activity: ActivityDislike, byActor: MActorSignature) { |
24 | const dislikeObject = activity.type === 'Dislike' | 24 | const dislikeObject = activity.object |
25 | ? activity.object | ||
26 | : (activity.object as DislikeObject).object | ||
27 | |||
28 | const byAccount = byActor.Account | 25 | const byAccount = byActor.Account |
29 | 26 | ||
30 | if (!byAccount) throw new Error('Cannot create dislike with the non account actor ' + byActor.url) | 27 | if (!byAccount) throw new Error('Cannot create dislike with the non account actor ' + byActor.url) |
diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 10f58ef27..bea285670 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts | |||
@@ -3,7 +3,7 @@ import { AccountModel } from '@server/models/account/account' | |||
3 | import { VideoModel } from '@server/models/video/video' | 3 | import { VideoModel } from '@server/models/video/video' |
4 | import { VideoCommentModel } from '@server/models/video/video-comment' | 4 | import { VideoCommentModel } from '@server/models/video/video-comment' |
5 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | 5 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' |
6 | import { AbuseObject, AbuseState, ActivityCreate, ActivityFlag } from '@shared/models' | 6 | import { AbuseState, ActivityFlag } from '@shared/models' |
7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
8 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
9 | import { sequelizeTypescript } from '../../../initializers/database' | 9 | import { sequelizeTypescript } from '../../../initializers/database' |
@@ -11,7 +11,7 @@ import { getAPId } from '../../../lib/activitypub/activity' | |||
11 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' | 11 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' |
12 | import { MAccountDefault, MActorSignature, MCommentOwnerVideo } from '../../../types/models' | 12 | import { MAccountDefault, MActorSignature, MCommentOwnerVideo } from '../../../types/models' |
13 | 13 | ||
14 | async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) { | 14 | async function processFlagActivity (options: APProcessorOptions<ActivityFlag>) { |
15 | const { activity, byActor } = options | 15 | const { activity, byActor } = options |
16 | 16 | ||
17 | return retryTransactionWrapper(processCreateAbuse, activity, byActor) | 17 | return retryTransactionWrapper(processCreateAbuse, activity, byActor) |
@@ -25,9 +25,7 @@ export { | |||
25 | 25 | ||
26 | // --------------------------------------------------------------------------- | 26 | // --------------------------------------------------------------------------- |
27 | 27 | ||
28 | async function processCreateAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) { | 28 | async function processCreateAbuse (flag: ActivityFlag, byActor: MActorSignature) { |
29 | const flag = activity.type === 'Flag' ? activity : (activity.object as AbuseObject) | ||
30 | |||
31 | const account = byActor.Account | 29 | const account = byActor.Account |
32 | if (!account) throw new Error('Cannot create abuse with the non account actor ' + byActor.url) | 30 | if (!account) throw new Error('Cannot create abuse with the non account actor ' + byActor.url) |
33 | 31 | ||
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index 99423a72b..25f68724d 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts | |||
@@ -1,6 +1,14 @@ | |||
1 | import { VideoModel } from '@server/models/video/video' | 1 | import { VideoModel } from '@server/models/video/video' |
2 | import { ActivityAnnounce, ActivityFollow, ActivityLike, ActivityUndo, CacheFileObject } from '../../../../shared/models/activitypub' | 2 | import { |
3 | import { DislikeObject } from '../../../../shared/models/activitypub/objects' | 3 | ActivityAnnounce, |
4 | ActivityCreate, | ||
5 | ActivityDislike, | ||
6 | ActivityFollow, | ||
7 | ActivityLike, | ||
8 | ActivityUndo, | ||
9 | ActivityUndoObject, | ||
10 | CacheFileObject | ||
11 | } from '../../../../shared/models/activitypub' | ||
4 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 12 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
5 | import { logger } from '../../../helpers/logger' | 13 | import { logger } from '../../../helpers/logger' |
6 | import { sequelizeTypescript } from '../../../initializers/database' | 14 | import { sequelizeTypescript } from '../../../initializers/database' |
@@ -11,10 +19,11 @@ import { VideoRedundancyModel } from '../../../models/redundancy/video-redundanc | |||
11 | import { VideoShareModel } from '../../../models/video/video-share' | 19 | import { VideoShareModel } from '../../../models/video/video-share' |
12 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' | 20 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' |
13 | import { MActorSignature } from '../../../types/models' | 21 | import { MActorSignature } from '../../../types/models' |
22 | import { fetchAPObject } from '../activity' | ||
14 | import { forwardVideoRelatedActivity } from '../send/shared/send-utils' | 23 | import { forwardVideoRelatedActivity } from '../send/shared/send-utils' |
15 | import { federateVideoIfNeeded, getOrCreateAPVideo } from '../videos' | 24 | import { federateVideoIfNeeded, getOrCreateAPVideo } from '../videos' |
16 | 25 | ||
17 | async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { | 26 | async function processUndoActivity (options: APProcessorOptions<ActivityUndo<ActivityUndoObject>>) { |
18 | const { activity, byActor } = options | 27 | const { activity, byActor } = options |
19 | const activityToUndo = activity.object | 28 | const activityToUndo = activity.object |
20 | 29 | ||
@@ -23,8 +32,10 @@ async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { | |||
23 | } | 32 | } |
24 | 33 | ||
25 | if (activityToUndo.type === 'Create') { | 34 | if (activityToUndo.type === 'Create') { |
26 | if (activityToUndo.object.type === 'CacheFile') { | 35 | const objectToUndo = await fetchAPObject<CacheFileObject>(activityToUndo.object) |
27 | return retryTransactionWrapper(processUndoCacheFile, byActor, activity) | 36 | |
37 | if (objectToUndo.type === 'CacheFile') { | ||
38 | return retryTransactionWrapper(processUndoCacheFile, byActor, activity, objectToUndo) | ||
28 | } | 39 | } |
29 | } | 40 | } |
30 | 41 | ||
@@ -53,8 +64,8 @@ export { | |||
53 | 64 | ||
54 | // --------------------------------------------------------------------------- | 65 | // --------------------------------------------------------------------------- |
55 | 66 | ||
56 | async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo) { | 67 | async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo<ActivityLike>) { |
57 | const likeActivity = activity.object as ActivityLike | 68 | const likeActivity = activity.object |
58 | 69 | ||
59 | const { video: onlyVideo } = await getOrCreateAPVideo({ videoObject: likeActivity.object }) | 70 | const { video: onlyVideo } = await getOrCreateAPVideo({ videoObject: likeActivity.object }) |
60 | // We don't care about likes of remote videos | 71 | // We don't care about likes of remote videos |
@@ -78,12 +89,10 @@ async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo | |||
78 | }) | 89 | }) |
79 | } | 90 | } |
80 | 91 | ||
81 | async function processUndoDislike (byActor: MActorSignature, activity: ActivityUndo) { | 92 | async function processUndoDislike (byActor: MActorSignature, activity: ActivityUndo<ActivityDislike>) { |
82 | const dislike = activity.object.type === 'Dislike' | 93 | const dislikeActivity = activity.object |
83 | ? activity.object | ||
84 | : activity.object.object as DislikeObject | ||
85 | 94 | ||
86 | const { video: onlyVideo } = await getOrCreateAPVideo({ videoObject: dislike.object }) | 95 | const { video: onlyVideo } = await getOrCreateAPVideo({ videoObject: dislikeActivity.object }) |
87 | // We don't care about likes of remote videos | 96 | // We don't care about likes of remote videos |
88 | if (!onlyVideo.isOwned()) return | 97 | if (!onlyVideo.isOwned()) return |
89 | 98 | ||
@@ -91,7 +100,7 @@ async function processUndoDislike (byActor: MActorSignature, activity: ActivityU | |||
91 | if (!byActor.Account) throw new Error('Unknown account ' + byActor.url) | 100 | if (!byActor.Account) throw new Error('Unknown account ' + byActor.url) |
92 | 101 | ||
93 | const video = await VideoModel.loadFull(onlyVideo.id, t) | 102 | const video = await VideoModel.loadFull(onlyVideo.id, t) |
94 | const rate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byActor.Account.id, video.id, dislike.id, t) | 103 | const rate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byActor.Account.id, video.id, dislikeActivity.id, t) |
95 | if (!rate || rate.type !== 'dislike') { | 104 | if (!rate || rate.type !== 'dislike') { |
96 | logger.warn(`Unknown dislike by account %d for video %d.`, byActor.Account.id, video.id) | 105 | logger.warn(`Unknown dislike by account %d for video %d.`, byActor.Account.id, video.id) |
97 | return | 106 | return |
@@ -107,9 +116,11 @@ async function processUndoDislike (byActor: MActorSignature, activity: ActivityU | |||
107 | 116 | ||
108 | // --------------------------------------------------------------------------- | 117 | // --------------------------------------------------------------------------- |
109 | 118 | ||
110 | async function processUndoCacheFile (byActor: MActorSignature, activity: ActivityUndo) { | 119 | async function processUndoCacheFile ( |
111 | const cacheFileObject = activity.object.object as CacheFileObject | 120 | byActor: MActorSignature, |
112 | 121 | activity: ActivityUndo<ActivityCreate<CacheFileObject>>, | |
122 | cacheFileObject: CacheFileObject | ||
123 | ) { | ||
113 | const { video } = await getOrCreateAPVideo({ videoObject: cacheFileObject.object }) | 124 | const { video } = await getOrCreateAPVideo({ videoObject: cacheFileObject.object }) |
114 | 125 | ||
115 | return sequelizeTypescript.transaction(async t => { | 126 | return sequelizeTypescript.transaction(async t => { |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 4afdbd430..9caa74e04 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { isRedundancyAccepted } from '@server/lib/redundancy' | 1 | import { isRedundancyAccepted } from '@server/lib/redundancy' |
2 | import { ActivityUpdate, CacheFileObject, VideoObject } from '../../../../shared/models/activitypub' | 2 | import { ActivityUpdate, ActivityUpdateObject, CacheFileObject, VideoObject } from '../../../../shared/models/activitypub' |
3 | import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor' | 3 | import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor' |
4 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | 4 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' |
5 | import { isCacheFileObjectValid } from '../../../helpers/custom-validators/activitypub/cache-file' | 5 | import { isCacheFileObjectValid } from '../../../helpers/custom-validators/activitypub/cache-file' |
@@ -10,16 +10,18 @@ import { sequelizeTypescript } from '../../../initializers/database' | |||
10 | import { ActorModel } from '../../../models/actor/actor' | 10 | import { ActorModel } from '../../../models/actor/actor' |
11 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' | 11 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' |
12 | import { MActorFull, MActorSignature } from '../../../types/models' | 12 | import { MActorFull, MActorSignature } from '../../../types/models' |
13 | import { fetchAPObject } from '../activity' | ||
13 | import { APActorUpdater } from '../actors/updater' | 14 | import { APActorUpdater } from '../actors/updater' |
14 | import { createOrUpdateCacheFile } from '../cache-file' | 15 | import { createOrUpdateCacheFile } from '../cache-file' |
15 | import { createOrUpdateVideoPlaylist } from '../playlists' | 16 | import { createOrUpdateVideoPlaylist } from '../playlists' |
16 | import { forwardVideoRelatedActivity } from '../send/shared/send-utils' | 17 | import { forwardVideoRelatedActivity } from '../send/shared/send-utils' |
17 | import { APVideoUpdater, getOrCreateAPVideo } from '../videos' | 18 | import { APVideoUpdater, getOrCreateAPVideo } from '../videos' |
18 | 19 | ||
19 | async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { | 20 | async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate<ActivityUpdateObject>>) { |
20 | const { activity, byActor } = options | 21 | const { activity, byActor } = options |
21 | 22 | ||
22 | const objectType = activity.object.type | 23 | const object = await fetchAPObject(activity.object) |
24 | const objectType = object.type | ||
23 | 25 | ||
24 | if (objectType === 'Video') { | 26 | if (objectType === 'Video') { |
25 | return retryTransactionWrapper(processUpdateVideo, activity) | 27 | return retryTransactionWrapper(processUpdateVideo, activity) |
@@ -28,17 +30,17 @@ async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate | |||
28 | if (objectType === 'Person' || objectType === 'Application' || objectType === 'Group') { | 30 | if (objectType === 'Person' || objectType === 'Application' || objectType === 'Group') { |
29 | // We need more attributes | 31 | // We need more attributes |
30 | const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url) | 32 | const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url) |
31 | return retryTransactionWrapper(processUpdateActor, byActorFull, activity) | 33 | return retryTransactionWrapper(processUpdateActor, byActorFull, object) |
32 | } | 34 | } |
33 | 35 | ||
34 | if (objectType === 'CacheFile') { | 36 | if (objectType === 'CacheFile') { |
35 | // We need more attributes | 37 | // We need more attributes |
36 | const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url) | 38 | const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url) |
37 | return retryTransactionWrapper(processUpdateCacheFile, byActorFull, activity) | 39 | return retryTransactionWrapper(processUpdateCacheFile, byActorFull, activity, object) |
38 | } | 40 | } |
39 | 41 | ||
40 | if (objectType === 'Playlist') { | 42 | if (objectType === 'Playlist') { |
41 | return retryTransactionWrapper(processUpdatePlaylist, byActor, activity) | 43 | return retryTransactionWrapper(processUpdatePlaylist, byActor, activity, object) |
42 | } | 44 | } |
43 | 45 | ||
44 | return undefined | 46 | return undefined |
@@ -52,7 +54,7 @@ export { | |||
52 | 54 | ||
53 | // --------------------------------------------------------------------------- | 55 | // --------------------------------------------------------------------------- |
54 | 56 | ||
55 | async function processUpdateVideo (activity: ActivityUpdate) { | 57 | async function processUpdateVideo (activity: ActivityUpdate<VideoObject | string>) { |
56 | const videoObject = activity.object as VideoObject | 58 | const videoObject = activity.object as VideoObject |
57 | 59 | ||
58 | if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { | 60 | if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { |
@@ -72,11 +74,13 @@ async function processUpdateVideo (activity: ActivityUpdate) { | |||
72 | return updater.update(activity.to) | 74 | return updater.update(activity.to) |
73 | } | 75 | } |
74 | 76 | ||
75 | async function processUpdateCacheFile (byActor: MActorSignature, activity: ActivityUpdate) { | 77 | async function processUpdateCacheFile ( |
78 | byActor: MActorSignature, | ||
79 | activity: ActivityUpdate<CacheFileObject | string>, | ||
80 | cacheFileObject: CacheFileObject | ||
81 | ) { | ||
76 | if (await isRedundancyAccepted(activity, byActor) !== true) return | 82 | if (await isRedundancyAccepted(activity, byActor) !== true) return |
77 | 83 | ||
78 | const cacheFileObject = activity.object as CacheFileObject | ||
79 | |||
80 | if (!isCacheFileObjectValid(cacheFileObject)) { | 84 | if (!isCacheFileObjectValid(cacheFileObject)) { |
81 | logger.debug('Cache file object sent by update is not valid.', { cacheFileObject }) | 85 | logger.debug('Cache file object sent by update is not valid.', { cacheFileObject }) |
82 | return undefined | 86 | return undefined |
@@ -96,19 +100,19 @@ async function processUpdateCacheFile (byActor: MActorSignature, activity: Activ | |||
96 | } | 100 | } |
97 | } | 101 | } |
98 | 102 | ||
99 | async function processUpdateActor (actor: MActorFull, activity: ActivityUpdate) { | 103 | async function processUpdateActor (actor: MActorFull, actorObject: ActivityPubActor) { |
100 | const actorObject = activity.object as ActivityPubActor | ||
101 | |||
102 | logger.debug('Updating remote account "%s".', actorObject.url) | 104 | logger.debug('Updating remote account "%s".', actorObject.url) |
103 | 105 | ||
104 | const updater = new APActorUpdater(actorObject, actor) | 106 | const updater = new APActorUpdater(actorObject, actor) |
105 | return updater.update() | 107 | return updater.update() |
106 | } | 108 | } |
107 | 109 | ||
108 | async function processUpdatePlaylist (byActor: MActorSignature, activity: ActivityUpdate) { | 110 | async function processUpdatePlaylist ( |
109 | const playlistObject = activity.object as PlaylistObject | 111 | byActor: MActorSignature, |
112 | activity: ActivityUpdate<PlaylistObject | string>, | ||
113 | playlistObject: PlaylistObject | ||
114 | ) { | ||
110 | const byAccount = byActor.Account | 115 | const byAccount = byActor.Account |
111 | |||
112 | if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url) | 116 | if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url) |
113 | 117 | ||
114 | await createOrUpdateVideoPlaylist(playlistObject, activity.to) | 118 | await createOrUpdateVideoPlaylist(playlistObject, activity.to) |
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index 0e996ab80..2cd4db14d 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -1,6 +1,14 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { getServerActor } from '@server/models/application/application' | 2 | import { getServerActor } from '@server/models/application/application' |
3 | import { ActivityAudience, ActivityCreate, ContextType, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | 3 | import { |
4 | ActivityAudience, | ||
5 | ActivityCreate, | ||
6 | ActivityCreateObject, | ||
7 | ContextType, | ||
8 | VideoCommentObject, | ||
9 | VideoPlaylistPrivacy, | ||
10 | VideoPrivacy | ||
11 | } from '@shared/models' | ||
4 | import { logger, loggerTagsFactory } from '../../../helpers/logger' | 12 | import { logger, loggerTagsFactory } from '../../../helpers/logger' |
5 | import { VideoCommentModel } from '../../../models/video/video-comment' | 13 | import { VideoCommentModel } from '../../../models/video/video-comment' |
6 | import { | 14 | import { |
@@ -107,7 +115,7 @@ async function sendCreateVideoComment (comment: MCommentOwnerVideo, transaction: | |||
107 | 115 | ||
108 | const byActor = comment.Account.Actor | 116 | const byActor = comment.Account.Actor |
109 | const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, transaction) | 117 | const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, transaction) |
110 | const commentObject = comment.toActivityPubObject(threadParentComments) | 118 | const commentObject = comment.toActivityPubObject(threadParentComments) as VideoCommentObject |
111 | 119 | ||
112 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, transaction) | 120 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, transaction) |
113 | // Add the actor that commented too | 121 | // Add the actor that commented too |
@@ -168,7 +176,12 @@ async function sendCreateVideoComment (comment: MCommentOwnerVideo, transaction: | |||
168 | }) | 176 | }) |
169 | } | 177 | } |
170 | 178 | ||
171 | function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate { | 179 | function buildCreateActivity <T extends ActivityCreateObject> ( |
180 | url: string, | ||
181 | byActor: MActorLight, | ||
182 | object: T, | ||
183 | audience?: ActivityAudience | ||
184 | ): ActivityCreate<T> { | ||
172 | if (!audience) audience = getAudience(byActor) | 185 | if (!audience) audience = getAudience(byActor) |
173 | 186 | ||
174 | return audiencify( | 187 | return audiencify( |
@@ -176,7 +189,9 @@ function buildCreateActivity (url: string, byActor: MActorLight, object: any, au | |||
176 | type: 'Create' as 'Create', | 189 | type: 'Create' as 'Create', |
177 | id: url + '/activity', | 190 | id: url + '/activity', |
178 | actor: byActor.url, | 191 | actor: byActor.url, |
179 | object: audiencify(object, audience) | 192 | object: typeof object === 'string' |
193 | ? object | ||
194 | : audiencify(object, audience) | ||
180 | }, | 195 | }, |
181 | audience | 196 | audience |
182 | ) | 197 | ) |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index b8eb47ff6..b0b48c9c4 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -1,14 +1,5 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { | 2 | import { ActivityAudience, ActivityDislike, ActivityLike, ActivityUndo, ActivityUndoObject, ContextType } from '@shared/models' |
3 | ActivityAnnounce, | ||
4 | ActivityAudience, | ||
5 | ActivityCreate, | ||
6 | ActivityDislike, | ||
7 | ActivityFollow, | ||
8 | ActivityLike, | ||
9 | ActivityUndo, | ||
10 | ContextType | ||
11 | } from '@shared/models' | ||
12 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
13 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
14 | import { | 5 | import { |
@@ -128,12 +119,12 @@ export { | |||
128 | 119 | ||
129 | // --------------------------------------------------------------------------- | 120 | // --------------------------------------------------------------------------- |
130 | 121 | ||
131 | function undoActivityData ( | 122 | function undoActivityData <T extends ActivityUndoObject> ( |
132 | url: string, | 123 | url: string, |
133 | byActor: MActorAudience, | 124 | byActor: MActorAudience, |
134 | object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, | 125 | object: T, |
135 | audience?: ActivityAudience | 126 | audience?: ActivityAudience |
136 | ): ActivityUndo { | 127 | ): ActivityUndo<T> { |
137 | if (!audience) audience = getAudience(byActor) | 128 | if (!audience) audience = getAudience(byActor) |
138 | 129 | ||
139 | return audiencify( | 130 | return audiencify( |
@@ -151,7 +142,7 @@ async function sendUndoVideoRelatedActivity (options: { | |||
151 | byActor: MActor | 142 | byActor: MActor |
152 | video: MVideoAccountLight | 143 | video: MVideoAccountLight |
153 | url: string | 144 | url: string |
154 | activity: ActivityFollow | ActivityCreate | ActivityAnnounce | 145 | activity: ActivityUndoObject |
155 | contextType: ContextType | 146 | contextType: ContextType |
156 | transaction: Transaction | 147 | transaction: Transaction |
157 | }) { | 148 | }) { |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 3d2b437e4..f3fb741c6 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { getServerActor } from '@server/models/application/application' | 2 | import { getServerActor } from '@server/models/application/application' |
3 | import { ActivityAudience, ActivityUpdate, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | 3 | import { ActivityAudience, ActivityUpdate, ActivityUpdateObject, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' |
4 | import { logger } from '../../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { AccountModel } from '../../../models/account/account' | 5 | import { AccountModel } from '../../../models/account/account' |
6 | import { VideoModel } from '../../../models/video/video' | 6 | import { VideoModel } from '../../../models/video/video' |
@@ -137,7 +137,12 @@ export { | |||
137 | 137 | ||
138 | // --------------------------------------------------------------------------- | 138 | // --------------------------------------------------------------------------- |
139 | 139 | ||
140 | function buildUpdateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityUpdate { | 140 | function buildUpdateActivity ( |
141 | url: string, | ||
142 | byActor: MActorLight, | ||
143 | object: ActivityUpdateObject, | ||
144 | audience?: ActivityAudience | ||
145 | ): ActivityUpdate<ActivityUpdateObject> { | ||
141 | if (!audience) audience = getAudience(byActor) | 146 | if (!audience) audience = getAudience(byActor) |
142 | 147 | ||
143 | return audiencify( | 148 | return audiencify( |
diff --git a/server/lib/activitypub/videos/get.ts b/server/lib/activitypub/videos/get.ts index 14ba55034..92387c5d4 100644 --- a/server/lib/activitypub/videos/get.ts +++ b/server/lib/activitypub/videos/get.ts | |||
@@ -3,7 +3,7 @@ import { logger } from '@server/helpers/logger' | |||
3 | import { JobQueue } from '@server/lib/job-queue' | 3 | import { JobQueue } from '@server/lib/job-queue' |
4 | import { loadVideoByUrl, VideoLoadByUrlType } from '@server/lib/model-loaders' | 4 | import { loadVideoByUrl, VideoLoadByUrlType } from '@server/lib/model-loaders' |
5 | import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' | 5 | import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' |
6 | import { APObject } from '@shared/models' | 6 | import { APObjectId } from '@shared/models' |
7 | import { getAPId } from '../activity' | 7 | import { getAPId } from '../activity' |
8 | import { refreshVideoIfNeeded } from './refresh' | 8 | import { refreshVideoIfNeeded } from './refresh' |
9 | import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' | 9 | import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' |
@@ -15,21 +15,21 @@ type GetVideoResult <T> = Promise<{ | |||
15 | }> | 15 | }> |
16 | 16 | ||
17 | type GetVideoParamAll = { | 17 | type GetVideoParamAll = { |
18 | videoObject: APObject | 18 | videoObject: APObjectId |
19 | syncParam?: SyncParam | 19 | syncParam?: SyncParam |
20 | fetchType?: 'all' | 20 | fetchType?: 'all' |
21 | allowRefresh?: boolean | 21 | allowRefresh?: boolean |
22 | } | 22 | } |
23 | 23 | ||
24 | type GetVideoParamImmutable = { | 24 | type GetVideoParamImmutable = { |
25 | videoObject: APObject | 25 | videoObject: APObjectId |
26 | syncParam?: SyncParam | 26 | syncParam?: SyncParam |
27 | fetchType: 'only-immutable-attributes' | 27 | fetchType: 'only-immutable-attributes' |
28 | allowRefresh: false | 28 | allowRefresh: false |
29 | } | 29 | } |
30 | 30 | ||
31 | type GetVideoParamOther = { | 31 | type GetVideoParamOther = { |
32 | videoObject: APObject | 32 | videoObject: APObjectId |
33 | syncParam?: SyncParam | 33 | syncParam?: SyncParam |
34 | fetchType?: 'all' | 'only-video' | 34 | fetchType?: 'all' | 'only-video' |
35 | allowRefresh?: boolean | 35 | allowRefresh?: boolean |