diff options
author | Chocobozzz <me@florianbigard.com> | 2019-08-22 10:43:11 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-08-22 10:43:11 +0200 |
commit | 5c5e587307a27e173333789b5b5167d35f468b01 (patch) | |
tree | 94e3721caf2e11d38fd5f4112c0fc98da89ac535 /server/lib/activitypub/process | |
parent | 1b42d73f44811eec1b7ddd72dd0d640a57c3376c (diff) | |
parent | b5fecbf44192144d1ca27c23a0b53922de288c10 (diff) | |
download | PeerTube-5c5e587307a27e173333789b5b5167d35f468b01.tar.gz PeerTube-5c5e587307a27e173333789b5b5167d35f468b01.tar.zst PeerTube-5c5e587307a27e173333789b5b5167d35f468b01.zip |
Merge branch 'feature/strong-model-types' into develop
Diffstat (limited to 'server/lib/activitypub/process')
-rw-r--r-- | server/lib/activitypub/process/process-accept.ts | 5 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-announce.ts | 7 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 14 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-delete.ts | 26 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-dislike.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-flag.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-follow.ts | 21 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-like.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-reject.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-undo.ts | 12 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 15 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-view.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/process/process.ts | 11 |
13 files changed, 70 insertions, 65 deletions
diff --git a/server/lib/activitypub/process/process-accept.ts b/server/lib/activitypub/process/process-accept.ts index cf27e6c32..86f7c764d 100644 --- a/server/lib/activitypub/process/process-accept.ts +++ b/server/lib/activitypub/process/process-accept.ts | |||
@@ -1,9 +1,8 @@ | |||
1 | import { ActivityAccept } from '../../../../shared/models/activitypub' | 1 | import { ActivityAccept } from '../../../../shared/models/activitypub' |
2 | import { ActorModel } from '../../../models/activitypub/actor' | ||
3 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 2 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
4 | import { addFetchOutboxJob } from '../actor' | 3 | import { addFetchOutboxJob } from '../actor' |
5 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 4 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
6 | import { SignatureActorModel } from '../../../typings/models' | 5 | import { MActorDefault, MActorSignature } from '../../../typings/models' |
7 | 6 | ||
8 | async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) { | 7 | async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) { |
9 | const { byActor: targetActor, inboxActor } = options | 8 | const { byActor: targetActor, inboxActor } = options |
@@ -20,7 +19,7 @@ export { | |||
20 | 19 | ||
21 | // --------------------------------------------------------------------------- | 20 | // --------------------------------------------------------------------------- |
22 | 21 | ||
23 | async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) { | 22 | async function processAccept (actor: MActorDefault, targetActor: MActorSignature) { |
24 | const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) | 23 | const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) |
25 | if (!follow) throw new Error('Cannot find associated follow.') | 24 | if (!follow) throw new Error('Cannot find associated follow.') |
26 | 25 | ||
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index b3cdc4441..7e22125d5 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts | |||
@@ -5,10 +5,9 @@ import { VideoShareModel } from '../../../models/video/video-share' | |||
5 | import { forwardVideoRelatedActivity } from '../send/utils' | 5 | import { forwardVideoRelatedActivity } from '../send/utils' |
6 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' | 6 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' |
7 | import { Notifier } from '../../notifier' | 7 | import { Notifier } from '../../notifier' |
8 | import { VideoModel } from '../../../models/video/video' | ||
9 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
10 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 9 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
11 | import { SignatureActorModel } from '../../../typings/models' | 10 | import { MActorSignature, MVideoAccountLightBlacklistAllFiles } from '../../../typings/models' |
12 | 11 | ||
13 | async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) { | 12 | async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) { |
14 | const { activity, byActor: actorAnnouncer } = options | 13 | const { activity, byActor: actorAnnouncer } = options |
@@ -26,10 +25,10 @@ export { | |||
26 | 25 | ||
27 | // --------------------------------------------------------------------------- | 26 | // --------------------------------------------------------------------------- |
28 | 27 | ||
29 | async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) { | 28 | async function processVideoShare (actorAnnouncer: MActorSignature, activity: ActivityAnnounce, notify: boolean) { |
30 | const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id | 29 | const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id |
31 | 30 | ||
32 | let video: VideoModel | 31 | let video: MVideoAccountLightBlacklistAllFiles |
33 | let videoCreated: boolean | 32 | let videoCreated: boolean |
34 | 33 | ||
35 | try { | 34 | try { |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 6815c6997..bee853721 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -10,10 +10,8 @@ import { createOrUpdateCacheFile } from '../cache-file' | |||
10 | import { Notifier } from '../../notifier' | 10 | import { Notifier } from '../../notifier' |
11 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | 11 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' |
12 | import { createOrUpdateVideoPlaylist } from '../playlist' | 12 | import { createOrUpdateVideoPlaylist } from '../playlist' |
13 | import { VideoModel } from '../../../models/video/video' | ||
14 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 13 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
15 | import { VideoCommentModel } from '../../../models/video/video-comment' | 14 | import { MActorSignature, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../../typings/models' |
16 | import { SignatureActorModel } from '../../../typings/models' | ||
17 | 15 | ||
18 | async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) { | 16 | async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) { |
19 | const { activity, byActor } = options | 17 | const { activity, byActor } = options |
@@ -61,7 +59,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) { | |||
61 | return video | 59 | return video |
62 | } | 60 | } |
63 | 61 | ||
64 | async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) { | 62 | async function processCreateCacheFile (activity: ActivityCreate, byActor: MActorSignature) { |
65 | const cacheFile = activity.object as CacheFileObject | 63 | const cacheFile = activity.object as CacheFileObject |
66 | 64 | ||
67 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) | 65 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) |
@@ -77,15 +75,15 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: Signat | |||
77 | } | 75 | } |
78 | } | 76 | } |
79 | 77 | ||
80 | async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) { | 78 | async function processCreateVideoComment (activity: ActivityCreate, byActor: MActorSignature, notify: boolean) { |
81 | const commentObject = activity.object as VideoCommentObject | 79 | const commentObject = activity.object as VideoCommentObject |
82 | const byAccount = byActor.Account | 80 | const byAccount = byActor.Account |
83 | 81 | ||
84 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) | 82 | if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) |
85 | 83 | ||
86 | let video: VideoModel | 84 | let video: MVideoAccountLightBlacklistAllFiles |
87 | let created: boolean | 85 | let created: boolean |
88 | let comment: VideoCommentModel | 86 | let comment: MCommentOwnerVideo |
89 | try { | 87 | try { |
90 | const resolveThreadResult = await resolveThread({ url: commentObject.id, isVideo: false }) | 88 | const resolveThreadResult = await resolveThread({ url: commentObject.id, isVideo: false }) |
91 | video = resolveThreadResult.video | 89 | video = resolveThreadResult.video |
@@ -110,7 +108,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Sig | |||
110 | if (created && notify) Notifier.Instance.notifyOnNewComment(comment) | 108 | if (created && notify) Notifier.Instance.notifyOnNewComment(comment) |
111 | } | 109 | } |
112 | 110 | ||
113 | async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) { | 111 | async function processCreatePlaylist (activity: ActivityCreate, byActor: MActorSignature) { |
114 | const playlistObject = activity.object as PlaylistObject | 112 | const playlistObject = activity.object as PlaylistObject |
115 | const byAccount = byActor.Account | 113 | const byAccount = byActor.Account |
116 | 114 | ||
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 344d14322..79d0e0d79 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts | |||
@@ -2,15 +2,13 @@ import { ActivityDelete } from '../../../../shared/models/activitypub' | |||
2 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 2 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { sequelizeTypescript } from '../../../initializers' | 4 | import { sequelizeTypescript } from '../../../initializers' |
5 | import { AccountModel } from '../../../models/account/account' | ||
6 | import { ActorModel } from '../../../models/activitypub/actor' | 5 | import { ActorModel } from '../../../models/activitypub/actor' |
7 | import { VideoModel } from '../../../models/video/video' | 6 | import { VideoModel } from '../../../models/video/video' |
8 | import { VideoChannelModel } from '../../../models/video/video-channel' | ||
9 | import { VideoCommentModel } from '../../../models/video/video-comment' | 7 | import { VideoCommentModel } from '../../../models/video/video-comment' |
10 | import { forwardVideoRelatedActivity } from '../send/utils' | 8 | import { forwardVideoRelatedActivity } from '../send/utils' |
11 | import { VideoPlaylistModel } from '../../../models/video/video-playlist' | 9 | import { VideoPlaylistModel } from '../../../models/video/video-playlist' |
12 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 10 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
13 | import { SignatureActorModel } from '../../../typings/models' | 11 | import { MAccountActor, MActor, MActorSignature, MChannelActor, MChannelActorAccountActor } from '../../../typings/models' |
14 | 12 | ||
15 | async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) { | 13 | async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) { |
16 | const { activity, byActor } = options | 14 | const { activity, byActor } = options |
@@ -24,13 +22,17 @@ async function processDeleteActivity (options: APProcessorOptions<ActivityDelete | |||
24 | if (byActorFull.type === 'Person') { | 22 | if (byActorFull.type === 'Person') { |
25 | if (!byActorFull.Account) throw new Error('Actor ' + byActorFull.url + ' is a person but we cannot find it in database.') | 23 | if (!byActorFull.Account) throw new Error('Actor ' + byActorFull.url + ' is a person but we cannot find it in database.') |
26 | 24 | ||
27 | byActorFull.Account.Actor = await byActorFull.Account.$get('Actor') as ActorModel | 25 | const accountToDelete = byActorFull.Account as MAccountActor |
28 | return retryTransactionWrapper(processDeleteAccount, byActorFull.Account) | 26 | accountToDelete.Actor = byActorFull |
27 | |||
28 | return retryTransactionWrapper(processDeleteAccount, accountToDelete) | ||
29 | } else if (byActorFull.type === 'Group') { | 29 | } else if (byActorFull.type === 'Group') { |
30 | if (!byActorFull.VideoChannel) throw new Error('Actor ' + byActorFull.url + ' is a group but we cannot find it in database.') | 30 | if (!byActorFull.VideoChannel) throw new Error('Actor ' + byActorFull.url + ' is a group but we cannot find it in database.') |
31 | 31 | ||
32 | byActorFull.VideoChannel.Actor = await byActorFull.VideoChannel.$get('Actor') as ActorModel | 32 | const channelToDelete = byActorFull.VideoChannel as MChannelActorAccountActor |
33 | return retryTransactionWrapper(processDeleteVideoChannel, byActorFull.VideoChannel) | 33 | channelToDelete.Actor = byActorFull |
34 | |||
35 | return retryTransactionWrapper(processDeleteVideoChannel, channelToDelete) | ||
34 | } | 36 | } |
35 | } | 37 | } |
36 | 38 | ||
@@ -70,7 +72,7 @@ export { | |||
70 | 72 | ||
71 | // --------------------------------------------------------------------------- | 73 | // --------------------------------------------------------------------------- |
72 | 74 | ||
73 | async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel) { | 75 | async function processDeleteVideo (actor: MActor, videoToDelete: VideoModel) { |
74 | logger.debug('Removing remote video "%s".', videoToDelete.uuid) | 76 | logger.debug('Removing remote video "%s".', videoToDelete.uuid) |
75 | 77 | ||
76 | await sequelizeTypescript.transaction(async t => { | 78 | await sequelizeTypescript.transaction(async t => { |
@@ -84,7 +86,7 @@ async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel) | |||
84 | logger.info('Remote video with uuid %s removed.', videoToDelete.uuid) | 86 | logger.info('Remote video with uuid %s removed.', videoToDelete.uuid) |
85 | } | 87 | } |
86 | 88 | ||
87 | async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: VideoPlaylistModel) { | 89 | async function processDeleteVideoPlaylist (actor: MActor, playlistToDelete: VideoPlaylistModel) { |
88 | logger.debug('Removing remote video playlist "%s".', playlistToDelete.uuid) | 90 | logger.debug('Removing remote video playlist "%s".', playlistToDelete.uuid) |
89 | 91 | ||
90 | await sequelizeTypescript.transaction(async t => { | 92 | await sequelizeTypescript.transaction(async t => { |
@@ -98,7 +100,7 @@ async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: | |||
98 | logger.info('Remote video playlist with uuid %s removed.', playlistToDelete.uuid) | 100 | logger.info('Remote video playlist with uuid %s removed.', playlistToDelete.uuid) |
99 | } | 101 | } |
100 | 102 | ||
101 | async function processDeleteAccount (accountToRemove: AccountModel) { | 103 | async function processDeleteAccount (accountToRemove: MAccountActor) { |
102 | logger.debug('Removing remote account "%s".', accountToRemove.Actor.url) | 104 | logger.debug('Removing remote account "%s".', accountToRemove.Actor.url) |
103 | 105 | ||
104 | await sequelizeTypescript.transaction(async t => { | 106 | await sequelizeTypescript.transaction(async t => { |
@@ -108,7 +110,7 @@ async function processDeleteAccount (accountToRemove: AccountModel) { | |||
108 | logger.info('Remote account %s removed.', accountToRemove.Actor.url) | 110 | logger.info('Remote account %s removed.', accountToRemove.Actor.url) |
109 | } | 111 | } |
110 | 112 | ||
111 | async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { | 113 | async function processDeleteVideoChannel (videoChannelToRemove: MChannelActor) { |
112 | logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url) | 114 | logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url) |
113 | 115 | ||
114 | await sequelizeTypescript.transaction(async t => { | 116 | await sequelizeTypescript.transaction(async t => { |
@@ -118,7 +120,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode | |||
118 | logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) | 120 | logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) |
119 | } | 121 | } |
120 | 122 | ||
121 | function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { | 123 | function processDeleteVideoComment (byActor: MActorSignature, videoComment: VideoCommentModel, activity: ActivityDelete) { |
122 | logger.debug('Removing remote video comment "%s".', videoComment.url) | 124 | logger.debug('Removing remote video comment "%s".', videoComment.url) |
123 | 125 | ||
124 | return sequelizeTypescript.transaction(async t => { | 126 | return sequelizeTypescript.transaction(async t => { |
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index 727fcfee0..debd8a67c 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts | |||
@@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' | |||
7 | import { forwardVideoRelatedActivity } from '../send/utils' | 7 | import { forwardVideoRelatedActivity } from '../send/utils' |
8 | import { getVideoDislikeActivityPubUrl } from '../url' | 8 | import { getVideoDislikeActivityPubUrl } from '../url' |
9 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 9 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
10 | import { SignatureActorModel } from '../../../typings/models' | 10 | import { MActorSignature } from '../../../typings/models' |
11 | 11 | ||
12 | async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { | 12 | async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { |
13 | const { activity, byActor } = options | 13 | const { activity, byActor } = options |
@@ -22,7 +22,7 @@ export { | |||
22 | 22 | ||
23 | // --------------------------------------------------------------------------- | 23 | // --------------------------------------------------------------------------- |
24 | 24 | ||
25 | async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) { | 25 | async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) { |
26 | const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object | 26 | const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object |
27 | const byAccount = byActor.Account | 27 | const byAccount = byActor.Account |
28 | 28 | ||
diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 1f8a80c14..422386540 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts | |||
@@ -8,7 +8,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' | |||
8 | import { Notifier } from '../../notifier' | 8 | import { Notifier } from '../../notifier' |
9 | import { getAPId } from '../../../helpers/activitypub' | 9 | import { getAPId } from '../../../helpers/activitypub' |
10 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 10 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
11 | import { SignatureActorModel } from '../../../typings/models' | 11 | import { MActorSignature, MVideoAbuseVideo } from '../../../typings/models' |
12 | 12 | ||
13 | async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) { | 13 | async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) { |
14 | const { activity, byActor } = options | 14 | const { activity, byActor } = options |
@@ -23,7 +23,7 @@ export { | |||
23 | 23 | ||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
25 | 25 | ||
26 | async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) { | 26 | async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) { |
27 | const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) | 27 | const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) |
28 | 28 | ||
29 | logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) | 29 | logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) |
@@ -41,7 +41,7 @@ async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, | |||
41 | state: VideoAbuseState.PENDING | 41 | state: VideoAbuseState.PENDING |
42 | } | 42 | } |
43 | 43 | ||
44 | const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) | 44 | const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo |
45 | videoAbuseInstance.Video = video | 45 | videoAbuseInstance.Video = video |
46 | 46 | ||
47 | logger.info('Remote abuse for video uuid %s created', flag.object) | 47 | logger.info('Remote abuse for video uuid %s created', flag.object) |
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 240aa5799..bc5660395 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts | |||
@@ -10,8 +10,7 @@ import { getAPId } from '../../../helpers/activitypub' | |||
10 | import { getServerActor } from '../../../helpers/utils' | 10 | import { getServerActor } from '../../../helpers/utils' |
11 | import { CONFIG } from '../../../initializers/config' | 11 | import { CONFIG } from '../../../initializers/config' |
12 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 12 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
13 | import { SignatureActorModel } from '../../../typings/models' | 13 | import { MAccount, MActorFollowActors, MActorFollowFull, MActorSignature } from '../../../typings/models' |
14 | import { ActorFollowModelLight } from '../../../typings/models/actor-follow' | ||
15 | 14 | ||
16 | async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { | 15 | async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { |
17 | const { activity, byActor } = options | 16 | const { activity, byActor } = options |
@@ -28,7 +27,7 @@ export { | |||
28 | 27 | ||
29 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
30 | 29 | ||
31 | async function processFollow (byActor: SignatureActorModel, targetActorURL: string) { | 30 | async function processFollow (byActor: MActorSignature, targetActorURL: string) { |
32 | const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { | 31 | const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { |
33 | const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) | 32 | const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) |
34 | 33 | ||
@@ -43,10 +42,10 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri | |||
43 | 42 | ||
44 | await sendReject(byActor, targetActor) | 43 | await sendReject(byActor, targetActor) |
45 | 44 | ||
46 | return { actorFollow: undefined } | 45 | return { actorFollow: undefined as MActorFollowActors } |
47 | } | 46 | } |
48 | 47 | ||
49 | const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ | 48 | const [ actorFollow, created ] = await ActorFollowModel.findOrCreate<MActorFollowActors>({ |
50 | where: { | 49 | where: { |
51 | actorId: byActor.id, | 50 | actorId: byActor.id, |
52 | targetActorId: targetActor.id | 51 | targetActorId: targetActor.id |
@@ -57,7 +56,7 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri | |||
57 | state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' | 56 | state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' |
58 | }, | 57 | }, |
59 | transaction: t | 58 | transaction: t |
60 | }) as [ ActorFollowModelLight, boolean ] | 59 | }) |
61 | 60 | ||
62 | if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { | 61 | if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { |
63 | actorFollow.state = 'accepted' | 62 | actorFollow.state = 'accepted' |
@@ -77,8 +76,14 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri | |||
77 | if (!actorFollow) return | 76 | if (!actorFollow) return |
78 | 77 | ||
79 | if (created) { | 78 | if (created) { |
80 | if (isFollowingInstance) Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) | 79 | if (isFollowingInstance) { |
81 | else Notifier.Instance.notifyOfNewUserFollow(actorFollow) | 80 | Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) |
81 | } else { | ||
82 | const actorFollowFull = actorFollow as MActorFollowFull | ||
83 | actorFollowFull.ActorFollower.Account = await actorFollow.ActorFollower.$get('Account') as MAccount | ||
84 | |||
85 | Notifier.Instance.notifyOfNewUserFollow(actorFollowFull) | ||
86 | } | ||
82 | } | 87 | } |
83 | 88 | ||
84 | logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) | 89 | logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) |
diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index cf559af72..62be0de42 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts | |||
@@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' | |||
7 | import { getVideoLikeActivityPubUrl } from '../url' | 7 | import { getVideoLikeActivityPubUrl } from '../url' |
8 | import { getAPId } from '../../../helpers/activitypub' | 8 | import { getAPId } from '../../../helpers/activitypub' |
9 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 9 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
10 | import { SignatureActorModel } from '../../../typings/models' | 10 | import { MActorSignature } from '../../../typings/models' |
11 | 11 | ||
12 | async function processLikeActivity (options: APProcessorOptions<ActivityLike>) { | 12 | async function processLikeActivity (options: APProcessorOptions<ActivityLike>) { |
13 | const { activity, byActor } = options | 13 | const { activity, byActor } = options |
@@ -22,7 +22,7 @@ export { | |||
22 | 22 | ||
23 | // --------------------------------------------------------------------------- | 23 | // --------------------------------------------------------------------------- |
24 | 24 | ||
25 | async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) { | 25 | async function processLikeVideo (byActor: MActorSignature, activity: ActivityLike) { |
26 | const videoUrl = getAPId(activity.object) | 26 | const videoUrl = getAPId(activity.object) |
27 | 27 | ||
28 | const byAccount = byActor.Account | 28 | const byAccount = byActor.Account |
diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts index 22e311ceb..00e9afa10 100644 --- a/server/lib/activitypub/process/process-reject.ts +++ b/server/lib/activitypub/process/process-reject.ts | |||
@@ -2,7 +2,7 @@ import { ActivityReject } from '../../../../shared/models/activitypub/activity' | |||
2 | import { sequelizeTypescript } from '../../../initializers' | 2 | import { sequelizeTypescript } from '../../../initializers' |
3 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 3 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
4 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 4 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
5 | import { ActorModelOnly } from '../../../typings/models' | 5 | import { MActor } from '../../../typings/models' |
6 | 6 | ||
7 | async function processRejectActivity (options: APProcessorOptions<ActivityReject>) { | 7 | async function processRejectActivity (options: APProcessorOptions<ActivityReject>) { |
8 | const { byActor: targetActor, inboxActor } = options | 8 | const { byActor: targetActor, inboxActor } = options |
@@ -19,7 +19,7 @@ export { | |||
19 | 19 | ||
20 | // --------------------------------------------------------------------------- | 20 | // --------------------------------------------------------------------------- |
21 | 21 | ||
22 | async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) { | 22 | async function processReject (follower: MActor, targetActor: MActor) { |
23 | return sequelizeTypescript.transaction(async t => { | 23 | return sequelizeTypescript.transaction(async t => { |
24 | const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) | 24 | const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) |
25 | 25 | ||
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index c37ee38bb..10643b2e9 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts | |||
@@ -11,7 +11,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' | |||
11 | import { VideoShareModel } from '../../../models/video/video-share' | 11 | import { VideoShareModel } from '../../../models/video/video-share' |
12 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | 12 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' |
13 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 13 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
14 | import { SignatureActorModel } from '../../../typings/models' | 14 | import { MActorSignature } from '../../../typings/models' |
15 | 15 | ||
16 | async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { | 16 | async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { |
17 | const { activity, byActor } = options | 17 | const { activity, byActor } = options |
@@ -54,7 +54,7 @@ export { | |||
54 | 54 | ||
55 | // --------------------------------------------------------------------------- | 55 | // --------------------------------------------------------------------------- |
56 | 56 | ||
57 | async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) { | 57 | async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo) { |
58 | const likeActivity = activity.object as ActivityLike | 58 | const likeActivity = activity.object as ActivityLike |
59 | 59 | ||
60 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) | 60 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) |
@@ -77,7 +77,7 @@ async function processUndoLike (byActor: SignatureActorModel, activity: Activity | |||
77 | }) | 77 | }) |
78 | } | 78 | } |
79 | 79 | ||
80 | async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) { | 80 | async function processUndoDislike (byActor: MActorSignature, activity: ActivityUndo) { |
81 | const dislike = activity.object.type === 'Dislike' | 81 | const dislike = activity.object.type === 'Dislike' |
82 | ? activity.object | 82 | ? activity.object |
83 | : activity.object.object as DislikeObject | 83 | : activity.object.object as DislikeObject |
@@ -102,7 +102,7 @@ async function processUndoDislike (byActor: SignatureActorModel, activity: Activ | |||
102 | }) | 102 | }) |
103 | } | 103 | } |
104 | 104 | ||
105 | async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) { | 105 | async function processUndoCacheFile (byActor: MActorSignature, activity: ActivityUndo) { |
106 | const cacheFileObject = activity.object.object as CacheFileObject | 106 | const cacheFileObject = activity.object.object as CacheFileObject |
107 | 107 | ||
108 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) | 108 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) |
@@ -127,7 +127,7 @@ async function processUndoCacheFile (byActor: SignatureActorModel, activity: Act | |||
127 | }) | 127 | }) |
128 | } | 128 | } |
129 | 129 | ||
130 | function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) { | 130 | function processUndoFollow (follower: MActorSignature, followActivity: ActivityFollow) { |
131 | return sequelizeTypescript.transaction(async t => { | 131 | return sequelizeTypescript.transaction(async t => { |
132 | const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) | 132 | const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) |
133 | const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) | 133 | const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) |
@@ -140,7 +140,7 @@ function processUndoFollow (follower: SignatureActorModel, followActivity: Activ | |||
140 | }) | 140 | }) |
141 | } | 141 | } |
142 | 142 | ||
143 | function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) { | 143 | function processUndoAnnounce (byActor: MActorSignature, announceActivity: ActivityAnnounce) { |
144 | return sequelizeTypescript.transaction(async t => { | 144 | return sequelizeTypescript.transaction(async t => { |
145 | const share = await VideoShareModel.loadByUrl(announceActivity.id, t) | 145 | const share = await VideoShareModel.loadByUrl(announceActivity.id, t) |
146 | if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) | 146 | if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 414f9e375..a47d605d8 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -15,7 +15,7 @@ import { forwardVideoRelatedActivity } from '../send/utils' | |||
15 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | 15 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' |
16 | import { createOrUpdateVideoPlaylist } from '../playlist' | 16 | import { createOrUpdateVideoPlaylist } from '../playlist' |
17 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 17 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
18 | import { SignatureActorModel } from '../../../typings/models' | 18 | import { MActorSignature, MAccountIdActor } from '../../../typings/models' |
19 | 19 | ||
20 | async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { | 20 | async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { |
21 | const { activity, byActor } = options | 21 | const { activity, byActor } = options |
@@ -53,7 +53,7 @@ export { | |||
53 | 53 | ||
54 | // --------------------------------------------------------------------------- | 54 | // --------------------------------------------------------------------------- |
55 | 55 | ||
56 | async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) { | 56 | async function processUpdateVideo (actor: MActorSignature, activity: ActivityUpdate) { |
57 | const videoObject = activity.object as VideoTorrentObject | 57 | const videoObject = activity.object as VideoTorrentObject |
58 | 58 | ||
59 | if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { | 59 | if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { |
@@ -61,20 +61,23 @@ async function processUpdateVideo (actor: SignatureActorModel, activity: Activit | |||
61 | return undefined | 61 | return undefined |
62 | } | 62 | } |
63 | 63 | ||
64 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false }) | 64 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false, fetchType: 'all' }) |
65 | const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) | 65 | const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) |
66 | 66 | ||
67 | const account = actor.Account as MAccountIdActor | ||
68 | account.Actor = actor | ||
69 | |||
67 | const updateOptions = { | 70 | const updateOptions = { |
68 | video, | 71 | video, |
69 | videoObject, | 72 | videoObject, |
70 | account: actor.Account, | 73 | account, |
71 | channel: channelActor.VideoChannel, | 74 | channel: channelActor.VideoChannel, |
72 | overrideTo: activity.to | 75 | overrideTo: activity.to |
73 | } | 76 | } |
74 | return updateVideoFromAP(updateOptions) | 77 | return updateVideoFromAP(updateOptions) |
75 | } | 78 | } |
76 | 79 | ||
77 | async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) { | 80 | async function processUpdateCacheFile (byActor: MActorSignature, activity: ActivityUpdate) { |
78 | const cacheFileObject = activity.object as CacheFileObject | 81 | const cacheFileObject = activity.object as CacheFileObject |
79 | 82 | ||
80 | if (!isCacheFileObjectValid(cacheFileObject)) { | 83 | if (!isCacheFileObjectValid(cacheFileObject)) { |
@@ -150,7 +153,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) | |||
150 | } | 153 | } |
151 | } | 154 | } |
152 | 155 | ||
153 | async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) { | 156 | async function processUpdatePlaylist (byActor: MActorSignature, activity: ActivityUpdate) { |
154 | const playlistObject = activity.object as PlaylistObject | 157 | const playlistObject = activity.object as PlaylistObject |
155 | const byAccount = byActor.Account | 158 | const byAccount = byActor.Account |
156 | 159 | ||
diff --git a/server/lib/activitypub/process/process-view.ts b/server/lib/activitypub/process/process-view.ts index e4997b828..df29ee968 100644 --- a/server/lib/activitypub/process/process-view.ts +++ b/server/lib/activitypub/process/process-view.ts | |||
@@ -3,7 +3,7 @@ import { forwardVideoRelatedActivity } from '../send/utils' | |||
3 | import { Redis } from '../../redis' | 3 | import { Redis } from '../../redis' |
4 | import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' | 4 | import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' |
5 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 5 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
6 | import { SignatureActorModel } from '../../../typings/models' | 6 | import { MActorSignature } from '../../../typings/models' |
7 | 7 | ||
8 | async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) { | 8 | async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) { |
9 | const { activity, byActor } = options | 9 | const { activity, byActor } = options |
@@ -18,11 +18,11 @@ export { | |||
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
21 | async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) { | 21 | async function processCreateView (activity: ActivityView | ActivityCreate, byActor: MActorSignature) { |
22 | const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object | 22 | const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object |
23 | 23 | ||
24 | const options = { | 24 | const options = { |
25 | videoObject: videoObject, | 25 | videoObject, |
26 | fetchType: 'only-video' as 'only-video' | 26 | fetchType: 'only-video' as 'only-video' |
27 | } | 27 | } |
28 | const { video } = await getOrCreateVideoAndAccountAndChannel(options) | 28 | const { video } = await getOrCreateVideoAndAccountAndChannel(options) |
diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index d108fe321..c602bf218 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import { Activity, ActivityType } from '../../../../shared/models/activitypub' | 1 | import { Activity, ActivityType } from '../../../../shared/models/activitypub' |
2 | import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub' | 2 | import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub' |
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { ActorModel } from '../../../models/activitypub/actor' | ||
5 | import { processAcceptActivity } from './process-accept' | 4 | import { processAcceptActivity } from './process-accept' |
6 | import { processAnnounceActivity } from './process-announce' | 5 | import { processAnnounceActivity } from './process-announce' |
7 | import { processCreateActivity } from './process-create' | 6 | import { processCreateActivity } from './process-create' |
@@ -16,7 +15,7 @@ import { processDislikeActivity } from './process-dislike' | |||
16 | import { processFlagActivity } from './process-flag' | 15 | import { processFlagActivity } from './process-flag' |
17 | import { processViewActivity } from './process-view' | 16 | import { processViewActivity } from './process-view' |
18 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' | 17 | import { APProcessorOptions } from '../../../typings/activitypub-processor.model' |
19 | import { SignatureActorModel } from '../../../typings/models' | 18 | import { MActorDefault, MActorSignature } from '../../../typings/models' |
20 | 19 | ||
21 | const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = { | 20 | const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = { |
22 | Create: processCreateActivity, | 21 | Create: processCreateActivity, |
@@ -36,15 +35,15 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Act | |||
36 | async function processActivities ( | 35 | async function processActivities ( |
37 | activities: Activity[], | 36 | activities: Activity[], |
38 | options: { | 37 | options: { |
39 | signatureActor?: SignatureActorModel | 38 | signatureActor?: MActorSignature |
40 | inboxActor?: ActorModel | 39 | inboxActor?: MActorDefault |
41 | outboxUrl?: string | 40 | outboxUrl?: string |
42 | fromFetch?: boolean | 41 | fromFetch?: boolean |
43 | } = {} | 42 | } = {} |
44 | ) { | 43 | ) { |
45 | const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options | 44 | const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options |
46 | 45 | ||
47 | const actorsCache: { [ url: string ]: SignatureActorModel } = {} | 46 | const actorsCache: { [ url: string ]: MActorSignature } = {} |
48 | 47 | ||
49 | for (const activity of activities) { | 48 | for (const activity of activities) { |
50 | if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) { | 49 | if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) { |
@@ -75,7 +74,7 @@ async function processActivities ( | |||
75 | } | 74 | } |
76 | 75 | ||
77 | try { | 76 | try { |
78 | await activityProcessor({ activity, byActor, inboxActor: inboxActor, fromFetch }) | 77 | await activityProcessor({ activity, byActor, inboxActor, fromFetch }) |
79 | } catch (err) { | 78 | } catch (err) { |
80 | logger.warn('Cannot process activity %s.', activity.type, { err }) | 79 | logger.warn('Cannot process activity %s.', activity.type, { err }) |
81 | } | 80 | } |