1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
import { ActivityCreate, CacheFileObject, VideoAbuseState, VideoTorrentObject } from '../../../../shared'
import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects'
import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { ActorModel } from '../../../models/activitypub/actor'
import { VideoAbuseModel } from '../../../models/video/video-abuse'
import { addVideoComment, resolveThread } from '../video-comments'
import { getOrCreateVideoAndAccountAndChannel } from '../videos'
import { forwardActivity, forwardVideoRelatedActivity } from '../send/utils'
import { Redis } from '../../redis'
import { createCacheFile } from '../cache-file'
async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) {
const activityObject = activity.object
const activityType = activityObject.type
if (activityType === 'View') {
return processCreateView(byActor, activity)
} else if (activityType === 'Dislike') {
return retryTransactionWrapper(processCreateDislike, byActor, activity)
} else if (activityType === 'Video') {
return processCreateVideo(activity)
} else if (activityType === 'Flag') {
return retryTransactionWrapper(processCreateVideoAbuse, byActor, activityObject as VideoAbuseObject)
} else if (activityType === 'Note') {
return retryTransactionWrapper(processCreateVideoComment, byActor, activity)
} else if (activityType === 'CacheFile') {
return retryTransactionWrapper(processCacheFile, byActor, activity)
}
logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id })
return Promise.resolve(undefined)
}
// ---------------------------------------------------------------------------
export {
processCreateActivity
}
// ---------------------------------------------------------------------------
async function processCreateVideo (activity: ActivityCreate) {
const videoToCreateData = activity.object as VideoTorrentObject
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoToCreateData })
return video
}
async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) {
const dislike = activity.object as DislikeObject
const byAccount = byActor.Account
if (!byAccount) throw new Error('Cannot create dislike with the non account actor ' + byActor.url)
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: dislike.object })
return sequelizeTypescript.transaction(async t => {
const rate = {
type: 'dislike' as 'dislike',
videoId: video.id,
accountId: byAccount.id
}
const [ , created ] = await AccountVideoRateModel.findOrCreate({
where: rate,
defaults: rate,
transaction: t
})
if (created === true) await video.increment('dislikes', { transaction: t })
if (video.isOwned() && created === true) {
// Don't resend the activity to the sender
const exceptions = [ byActor ]
await forwardVideoRelatedActivity(activity, t, exceptions, video)
}
})
}
async function processCreateView (byActor: ActorModel, activity: ActivityCreate) {
const view = activity.object as ViewObject
const options = {
videoObject: view.object,
fetchType: 'only-video' as 'only-video'
}
const { video } = await getOrCreateVideoAndAccountAndChannel(options)
await Redis.Instance.addVideoView(video.id)
if (video.isOwned()) {
// Don't resend the activity to the sender
const exceptions = [ byActor ]
await forwardActivity(activity, undefined, exceptions)
}
}
async function processCacheFile (byActor: ActorModel, activity: ActivityCreate) {
const cacheFile = activity.object as CacheFileObject
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object })
await createCacheFile(cacheFile, video, byActor)
if (video.isOwned()) {
// Don't resend the activity to the sender
const exceptions = [ byActor ]
await forwardActivity(activity, undefined, exceptions)
}
}
async function processCreateVideoAbuse (byActor: ActorModel, videoAbuseToCreateData: VideoAbuseObject) {
logger.debug('Reporting remote abuse for video %s.', videoAbuseToCreateData.object)
const account = byActor.Account
if (!account) throw new Error('Cannot create dislike with the non account actor ' + byActor.url)
const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoAbuseToCreateData.object })
return sequelizeTypescript.transaction(async t => {
const videoAbuseData = {
reporterAccountId: account.id,
reason: videoAbuseToCreateData.content,
videoId: video.id,
state: VideoAbuseState.PENDING
}
await VideoAbuseModel.create(videoAbuseData, { transaction: t })
logger.info('Remote abuse for video uuid %s created', videoAbuseToCreateData.object)
})
}
async function processCreateVideoComment (byActor: ActorModel, activity: ActivityCreate) {
const commentObject = activity.object as VideoCommentObject
const byAccount = byActor.Account
if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url)
const { video } = await resolveThread(commentObject.inReplyTo)
const { created } = await addVideoComment(video, commentObject.id)
if (video.isOwned() && created === true) {
// Don't resend the activity to the sender
const exceptions = [ byActor ]
await forwardVideoRelatedActivity(activity, undefined, exceptions, video)
}
}
|