]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/activitypub/client.ts
adding initial support for nodeinfo
[github/Chocobozzz/PeerTube.git] / server / controllers / activitypub / client.ts
CommitLineData
e4f97bab
C
1// Intercept ActivityPub client requests
2import * as express from 'express'
8fffe21a 3import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos'
d6e99e53 4import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub'
8fffe21a 5import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../initializers'
07197db4 6import { buildVideoAnnounce } from '../../lib/activitypub/send'
e251f170 7import { audiencify, getAudience } from '../../lib/activitypub/audience'
296c0905 8import { createActivityData } from '../../lib/activitypub/send/send-create'
3fd3ab2d 9import { asyncMiddleware, executeIfActivityPub, localAccountValidator } from '../../middlewares'
50d6de9c 10import { videoChannelsGetValidator, videosGetValidator, videosShareValidator } from '../../middlewares/validators'
da854ddd 11import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
3fd3ab2d 12import { AccountModel } from '../../models/account/account'
7006bc63 13import { ActorModel } from '../../models/activitypub/actor'
50d6de9c 14import { ActorFollowModel } from '../../models/activitypub/actor-follow'
3fd3ab2d
C
15import { VideoModel } from '../../models/video/video'
16import { VideoChannelModel } from '../../models/video/video-channel'
da854ddd 17import { VideoCommentModel } from '../../models/video/video-comment'
3fd3ab2d 18import { VideoShareModel } from '../../models/video/video-share'
3f6d68d9 19import { cache } from '../../middlewares/cache'
8fffe21a
C
20import { activityPubResponse } from './utils'
21import { AccountVideoRateModel } from '../../models/account/account-video-rate'
22import {
23 getVideoCommentsActivityPubUrl,
24 getVideoDislikesActivityPubUrl,
25 getVideoLikesActivityPubUrl,
26 getVideoSharesActivityPubUrl
27} from '../../lib/activitypub'
40e87e9e 28import { VideoCaptionModel } from '../../models/video/video-caption'
e4f97bab
C
29
30const activityPubClientRouter = express.Router()
31
108af661 32activityPubClientRouter.get('/accounts?/:name',
a2431b7d 33 executeIfActivityPub(asyncMiddleware(localAccountValidator)),
4e50b6a1 34 executeIfActivityPub(accountController)
e4f97bab 35)
7006bc63 36activityPubClientRouter.get('/accounts?/:name/followers',
a2431b7d 37 executeIfActivityPub(asyncMiddleware(localAccountValidator)),
e4f97bab
C
38 executeIfActivityPub(asyncMiddleware(accountFollowersController))
39)
7006bc63 40activityPubClientRouter.get('/accounts?/:name/following',
a2431b7d 41 executeIfActivityPub(asyncMiddleware(localAccountValidator)),
e4f97bab
C
42 executeIfActivityPub(asyncMiddleware(accountFollowingController))
43)
44
20494f12 45activityPubClientRouter.get('/videos/watch/:id',
3f6d68d9 46 executeIfActivityPub(asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS))),
a2431b7d 47 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
da854ddd 48 executeIfActivityPub(asyncMiddleware(videoController))
4e50b6a1 49)
296c0905
C
50activityPubClientRouter.get('/videos/watch/:id/activity',
51 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
52 executeIfActivityPub(asyncMiddleware(videoController))
53)
46531a0a
C
54activityPubClientRouter.get('/videos/watch/:id/announces',
55 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
56 executeIfActivityPub(asyncMiddleware(videoAnnouncesController))
57)
4e50b6a1
C
58activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
59 executeIfActivityPub(asyncMiddleware(videosShareValidator)),
60 executeIfActivityPub(asyncMiddleware(videoAnnounceController))
20494f12 61)
46531a0a
C
62activityPubClientRouter.get('/videos/watch/:id/likes',
63 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
64 executeIfActivityPub(asyncMiddleware(videoLikesController))
65)
66activityPubClientRouter.get('/videos/watch/:id/dislikes',
67 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
68 executeIfActivityPub(asyncMiddleware(videoDislikesController))
69)
70activityPubClientRouter.get('/videos/watch/:id/comments',
71 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
72 executeIfActivityPub(asyncMiddleware(videoCommentsController))
73)
da854ddd
C
74activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
75 executeIfActivityPub(asyncMiddleware(videoCommentGetValidator)),
76 executeIfActivityPub(asyncMiddleware(videoCommentController))
77)
296c0905
C
78activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity',
79 executeIfActivityPub(asyncMiddleware(videoCommentGetValidator)),
80 executeIfActivityPub(asyncMiddleware(videoCommentController))
81)
da854ddd 82
20494f12 83activityPubClientRouter.get('/video-channels/:id',
a2431b7d 84 executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)),
20494f12
C
85 executeIfActivityPub(asyncMiddleware(videoChannelController))
86)
7006bc63
C
87activityPubClientRouter.get('/video-channels/:id/followers',
88 executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)),
89 executeIfActivityPub(asyncMiddleware(videoChannelFollowersController))
90)
91activityPubClientRouter.get('/video-channels/:id/following',
92 executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)),
93 executeIfActivityPub(asyncMiddleware(videoChannelFollowingController))
94)
20494f12 95
e4f97bab
C
96// ---------------------------------------------------------------------------
97
98export {
99 activityPubClientRouter
100}
101
102// ---------------------------------------------------------------------------
103
4e50b6a1 104function accountController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 105 const account: AccountModel = res.locals.account
e4f97bab 106
4b8f09fa 107 return activityPubResponse(activityPubContextify(account.toActivityPubObject()), res)
e4f97bab
C
108}
109
110async function accountFollowersController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 111 const account: AccountModel = res.locals.account
7006bc63 112 const activityPubResult = await actorFollowers(req, account.Actor)
e4f97bab 113
4b8f09fa 114 return activityPubResponse(activityPubContextify(activityPubResult), res)
e4f97bab
C
115}
116
117async function accountFollowingController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 118 const account: AccountModel = res.locals.account
7006bc63 119 const activityPubResult = await actorFollowing(req, account.Actor)
e4f97bab 120
4b8f09fa 121 return activityPubResponse(activityPubContextify(activityPubResult), res)
e4f97bab 122}
20494f12 123
da854ddd 124async function videoController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 125 const video: VideoModel = res.locals.video
20494f12 126
40e87e9e
C
127 // We need captions to render AP object
128 video.VideoCaptions = await VideoCaptionModel.listVideoCaptions(video.id)
129
2186386c 130 const audience = getAudience(video.VideoChannel.Account.Actor, video.privacy === VideoPrivacy.PUBLIC)
8fffe21a 131 const videoObject = audiencify(video.toActivityPubObject(), audience)
2ccaeeb3 132
296c0905 133 if (req.path.endsWith('/activity')) {
2186386c 134 const data = createActivityData(video.url, video.VideoChannel.Account.Actor, videoObject, audience)
4b8f09fa 135 return activityPubResponse(activityPubContextify(data), res)
296c0905
C
136 }
137
4b8f09fa 138 return activityPubResponse(activityPubContextify(videoObject), res)
20494f12
C
139}
140
4e50b6a1 141async function videoAnnounceController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 142 const share = res.locals.videoShare as VideoShareModel
07197db4 143 const object = await buildVideoAnnounce(share.Actor, share, res.locals.video, undefined)
4e50b6a1 144
4b8f09fa 145 return activityPubResponse(activityPubContextify(object), res)
4e50b6a1
C
146}
147
46531a0a
C
148async function videoAnnouncesController (req: express.Request, res: express.Response, next: express.NextFunction) {
149 const video: VideoModel = res.locals.video
150
8fffe21a
C
151 const handler = async (start: number, count: number) => {
152 const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count)
153 return {
154 total: result.count,
155 data: result.rows.map(r => r.url)
156 }
157 }
158 const json = await activityPubCollectionPagination(getVideoSharesActivityPubUrl(video), handler, req.query.page)
46531a0a 159
8fffe21a 160 return activityPubResponse(activityPubContextify(json), res)
46531a0a
C
161}
162
163async function videoLikesController (req: express.Request, res: express.Response, next: express.NextFunction) {
164 const video: VideoModel = res.locals.video
8fffe21a 165 const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video))
46531a0a 166
8fffe21a 167 return activityPubResponse(activityPubContextify(json), res)
46531a0a
C
168}
169
170async function videoDislikesController (req: express.Request, res: express.Response, next: express.NextFunction) {
171 const video: VideoModel = res.locals.video
8fffe21a 172 const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video))
46531a0a 173
8fffe21a 174 return activityPubResponse(activityPubContextify(json), res)
46531a0a
C
175}
176
177async function videoCommentsController (req: express.Request, res: express.Response, next: express.NextFunction) {
178 const video: VideoModel = res.locals.video
179
8fffe21a
C
180 const handler = async (start: number, count: number) => {
181 const result = await VideoCommentModel.listAndCountByVideoId(video.id, start, count)
182 return {
183 total: result.count,
184 data: result.rows.map(r => r.url)
185 }
186 }
187 const json = await activityPubCollectionPagination(getVideoCommentsActivityPubUrl(video), handler, req.query.page)
46531a0a 188
8fffe21a 189 return activityPubResponse(activityPubContextify(json), res)
46531a0a
C
190}
191
20494f12 192async function videoChannelController (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 193 const videoChannel: VideoChannelModel = res.locals.videoChannel
20494f12 194
4b8f09fa 195 return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
20494f12 196}
da854ddd 197
7006bc63
C
198async function videoChannelFollowersController (req: express.Request, res: express.Response, next: express.NextFunction) {
199 const videoChannel: VideoChannelModel = res.locals.videoChannel
200 const activityPubResult = await actorFollowers(req, videoChannel.Actor)
201
4b8f09fa 202 return activityPubResponse(activityPubContextify(activityPubResult), res)
7006bc63
C
203}
204
205async function videoChannelFollowingController (req: express.Request, res: express.Response, next: express.NextFunction) {
206 const videoChannel: VideoChannelModel = res.locals.videoChannel
207 const activityPubResult = await actorFollowing(req, videoChannel.Actor)
208
4b8f09fa 209 return activityPubResponse(activityPubContextify(activityPubResult), res)
7006bc63
C
210}
211
da854ddd
C
212async function videoCommentController (req: express.Request, res: express.Response, next: express.NextFunction) {
213 const videoComment: VideoCommentModel = res.locals.videoComment
214
d7e70384 215 const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, undefined)
d6e99e53 216 const isPublic = true // Comments are always public
2186386c 217 const audience = getAudience(videoComment.Account.Actor, isPublic)
d6e99e53
C
218
219 const videoCommentObject = audiencify(videoComment.toActivityPubObject(threadParentComments), audience)
220
296c0905 221 if (req.path.endsWith('/activity')) {
2186386c 222 const data = createActivityData(videoComment.url, videoComment.Account.Actor, videoCommentObject, audience)
4b8f09fa 223 return activityPubResponse(activityPubContextify(data), res)
296c0905
C
224 }
225
4b8f09fa 226 return activityPubResponse(activityPubContextify(videoCommentObject), res)
da854ddd 227}
7006bc63
C
228
229// ---------------------------------------------------------------------------
230
231async function actorFollowing (req: express.Request, actor: ActorModel) {
8fffe21a
C
232 const handler = (start: number, count: number) => {
233 return ActorFollowModel.listAcceptedFollowingUrlsForApi([ actor.id ], undefined, start, count)
234 }
7006bc63 235
8fffe21a 236 return activityPubCollectionPagination(CONFIG.WEBSERVER.URL + req.url, handler, req.query.page)
7006bc63
C
237}
238
239async function actorFollowers (req: express.Request, actor: ActorModel) {
8fffe21a
C
240 const handler = (start: number, count: number) => {
241 return ActorFollowModel.listAcceptedFollowerUrlsForApi([ actor.id ], undefined, start, count)
242 }
7006bc63 243
8fffe21a 244 return activityPubCollectionPagination(CONFIG.WEBSERVER.URL + req.url, handler, req.query.page)
7006bc63 245}
4b8f09fa 246
8fffe21a
C
247function videoRates (req: express.Request, rateType: VideoRateType, video: VideoModel, url: string) {
248 const handler = async (start: number, count: number) => {
249 const result = await AccountVideoRateModel.listAndCountAccountUrlsByVideoId(rateType, video.id, start, count)
250 return {
251 total: result.count,
252 data: result.rows.map(r => r.Account.Actor.url)
253 }
254 }
255 return activityPubCollectionPagination(url, handler, req.query.page)
4b8f09fa 256}