diff options
Diffstat (limited to 'server/server/controllers/api/accounts.ts')
-rw-r--r-- | server/server/controllers/api/accounts.ts | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/server/server/controllers/api/accounts.ts b/server/server/controllers/api/accounts.ts new file mode 100644 index 000000000..b5fd4d133 --- /dev/null +++ b/server/server/controllers/api/accounts.ts | |||
@@ -0,0 +1,266 @@ | |||
1 | import express from 'express' | ||
2 | import { pickCommonVideoQuery } from '@server/helpers/query.js' | ||
3 | import { ActorFollowModel } from '@server/models/actor/actor-follow.js' | ||
4 | import { getServerActor } from '@server/models/application/application.js' | ||
5 | import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js' | ||
6 | import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils.js' | ||
7 | import { getFormattedObjects } from '../../helpers/utils.js' | ||
8 | import { JobQueue } from '../../lib/job-queue/index.js' | ||
9 | import { Hooks } from '../../lib/plugins/hooks.js' | ||
10 | import { | ||
11 | apiRateLimiter, | ||
12 | asyncMiddleware, | ||
13 | authenticate, | ||
14 | commonVideosFiltersValidator, | ||
15 | optionalAuthenticate, | ||
16 | paginationValidator, | ||
17 | setDefaultPagination, | ||
18 | setDefaultSort, | ||
19 | setDefaultVideosSort, | ||
20 | videoPlaylistsSortValidator, | ||
21 | videoRatesSortValidator, | ||
22 | videoRatingValidator | ||
23 | } from '../../middlewares/index.js' | ||
24 | import { | ||
25 | accountNameWithHostGetValidator, | ||
26 | accountsFollowersSortValidator, | ||
27 | accountsSortValidator, | ||
28 | ensureAuthUserOwnsAccountValidator, | ||
29 | ensureCanManageChannelOrAccount, | ||
30 | videoChannelsSortValidator, | ||
31 | videoChannelStatsValidator, | ||
32 | videoChannelSyncsSortValidator, | ||
33 | videosSortValidator | ||
34 | } from '../../middlewares/validators/index.js' | ||
35 | import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists.js' | ||
36 | import { AccountModel } from '../../models/account/account.js' | ||
37 | import { AccountVideoRateModel } from '../../models/account/account-video-rate.js' | ||
38 | import { guessAdditionalAttributesFromQuery } from '../../models/video/formatter/index.js' | ||
39 | import { VideoModel } from '../../models/video/video.js' | ||
40 | import { VideoChannelModel } from '../../models/video/video-channel.js' | ||
41 | import { VideoPlaylistModel } from '../../models/video/video-playlist.js' | ||
42 | |||
43 | const accountsRouter = express.Router() | ||
44 | |||
45 | accountsRouter.use(apiRateLimiter) | ||
46 | |||
47 | accountsRouter.get('/', | ||
48 | paginationValidator, | ||
49 | accountsSortValidator, | ||
50 | setDefaultSort, | ||
51 | setDefaultPagination, | ||
52 | asyncMiddleware(listAccounts) | ||
53 | ) | ||
54 | |||
55 | accountsRouter.get('/:accountName', | ||
56 | asyncMiddleware(accountNameWithHostGetValidator), | ||
57 | getAccount | ||
58 | ) | ||
59 | |||
60 | accountsRouter.get('/:accountName/videos', | ||
61 | asyncMiddleware(accountNameWithHostGetValidator), | ||
62 | paginationValidator, | ||
63 | videosSortValidator, | ||
64 | setDefaultVideosSort, | ||
65 | setDefaultPagination, | ||
66 | optionalAuthenticate, | ||
67 | commonVideosFiltersValidator, | ||
68 | asyncMiddleware(listAccountVideos) | ||
69 | ) | ||
70 | |||
71 | accountsRouter.get('/:accountName/video-channels', | ||
72 | asyncMiddleware(accountNameWithHostGetValidator), | ||
73 | videoChannelStatsValidator, | ||
74 | paginationValidator, | ||
75 | videoChannelsSortValidator, | ||
76 | setDefaultSort, | ||
77 | setDefaultPagination, | ||
78 | asyncMiddleware(listAccountChannels) | ||
79 | ) | ||
80 | |||
81 | accountsRouter.get('/:accountName/video-channel-syncs', | ||
82 | authenticate, | ||
83 | asyncMiddleware(accountNameWithHostGetValidator), | ||
84 | ensureCanManageChannelOrAccount, | ||
85 | paginationValidator, | ||
86 | videoChannelSyncsSortValidator, | ||
87 | setDefaultSort, | ||
88 | setDefaultPagination, | ||
89 | asyncMiddleware(listAccountChannelsSync) | ||
90 | ) | ||
91 | |||
92 | accountsRouter.get('/:accountName/video-playlists', | ||
93 | optionalAuthenticate, | ||
94 | asyncMiddleware(accountNameWithHostGetValidator), | ||
95 | paginationValidator, | ||
96 | videoPlaylistsSortValidator, | ||
97 | setDefaultSort, | ||
98 | setDefaultPagination, | ||
99 | commonVideoPlaylistFiltersValidator, | ||
100 | videoPlaylistsSearchValidator, | ||
101 | asyncMiddleware(listAccountPlaylists) | ||
102 | ) | ||
103 | |||
104 | accountsRouter.get('/:accountName/ratings', | ||
105 | authenticate, | ||
106 | asyncMiddleware(accountNameWithHostGetValidator), | ||
107 | ensureAuthUserOwnsAccountValidator, | ||
108 | paginationValidator, | ||
109 | videoRatesSortValidator, | ||
110 | setDefaultSort, | ||
111 | setDefaultPagination, | ||
112 | videoRatingValidator, | ||
113 | asyncMiddleware(listAccountRatings) | ||
114 | ) | ||
115 | |||
116 | accountsRouter.get('/:accountName/followers', | ||
117 | authenticate, | ||
118 | asyncMiddleware(accountNameWithHostGetValidator), | ||
119 | ensureAuthUserOwnsAccountValidator, | ||
120 | paginationValidator, | ||
121 | accountsFollowersSortValidator, | ||
122 | setDefaultSort, | ||
123 | setDefaultPagination, | ||
124 | asyncMiddleware(listAccountFollowers) | ||
125 | ) | ||
126 | |||
127 | // --------------------------------------------------------------------------- | ||
128 | |||
129 | export { | ||
130 | accountsRouter | ||
131 | } | ||
132 | |||
133 | // --------------------------------------------------------------------------- | ||
134 | |||
135 | function getAccount (req: express.Request, res: express.Response) { | ||
136 | const account = res.locals.account | ||
137 | |||
138 | if (account.isOutdated()) { | ||
139 | JobQueue.Instance.createJobAsync({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) | ||
140 | } | ||
141 | |||
142 | return res.json(account.toFormattedJSON()) | ||
143 | } | ||
144 | |||
145 | async function listAccounts (req: express.Request, res: express.Response) { | ||
146 | const resultList = await AccountModel.listForApi(req.query.start, req.query.count, req.query.sort) | ||
147 | |||
148 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
149 | } | ||
150 | |||
151 | async function listAccountChannels (req: express.Request, res: express.Response) { | ||
152 | const options = { | ||
153 | accountId: res.locals.account.id, | ||
154 | start: req.query.start, | ||
155 | count: req.query.count, | ||
156 | sort: req.query.sort, | ||
157 | withStats: req.query.withStats, | ||
158 | search: req.query.search | ||
159 | } | ||
160 | |||
161 | const resultList = await VideoChannelModel.listByAccountForAPI(options) | ||
162 | |||
163 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
164 | } | ||
165 | |||
166 | async function listAccountChannelsSync (req: express.Request, res: express.Response) { | ||
167 | const options = { | ||
168 | accountId: res.locals.account.id, | ||
169 | start: req.query.start, | ||
170 | count: req.query.count, | ||
171 | sort: req.query.sort, | ||
172 | search: req.query.search | ||
173 | } | ||
174 | |||
175 | const resultList = await VideoChannelSyncModel.listByAccountForAPI(options) | ||
176 | |||
177 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
178 | } | ||
179 | |||
180 | async function listAccountPlaylists (req: express.Request, res: express.Response) { | ||
181 | const serverActor = await getServerActor() | ||
182 | |||
183 | // Allow users to see their private/unlisted video playlists | ||
184 | let listMyPlaylists = false | ||
185 | if (res.locals.oauth && res.locals.oauth.token.User.Account.id === res.locals.account.id) { | ||
186 | listMyPlaylists = true | ||
187 | } | ||
188 | |||
189 | const resultList = await VideoPlaylistModel.listForApi({ | ||
190 | search: req.query.search, | ||
191 | followerActorId: serverActor.id, | ||
192 | start: req.query.start, | ||
193 | count: req.query.count, | ||
194 | sort: req.query.sort, | ||
195 | accountId: res.locals.account.id, | ||
196 | listMyPlaylists, | ||
197 | type: req.query.playlistType | ||
198 | }) | ||
199 | |||
200 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
201 | } | ||
202 | |||
203 | async function listAccountVideos (req: express.Request, res: express.Response) { | ||
204 | const serverActor = await getServerActor() | ||
205 | |||
206 | const account = res.locals.account | ||
207 | |||
208 | const displayOnlyForFollower = isUserAbleToSearchRemoteURI(res) | ||
209 | ? null | ||
210 | : { | ||
211 | actorId: serverActor.id, | ||
212 | orLocalVideos: true | ||
213 | } | ||
214 | |||
215 | const countVideos = getCountVideos(req) | ||
216 | const query = pickCommonVideoQuery(req.query) | ||
217 | |||
218 | const apiOptions = await Hooks.wrapObject({ | ||
219 | ...query, | ||
220 | |||
221 | displayOnlyForFollower, | ||
222 | nsfw: buildNSFWFilter(res, query.nsfw), | ||
223 | accountId: account.id, | ||
224 | user: res.locals.oauth ? res.locals.oauth.token.User : undefined, | ||
225 | countVideos | ||
226 | }, 'filter:api.accounts.videos.list.params') | ||
227 | |||
228 | const resultList = await Hooks.wrapPromiseFun( | ||
229 | VideoModel.listForApi, | ||
230 | apiOptions, | ||
231 | 'filter:api.accounts.videos.list.result' | ||
232 | ) | ||
233 | |||
234 | return res.json(getFormattedObjects(resultList.data, resultList.total, guessAdditionalAttributesFromQuery(query))) | ||
235 | } | ||
236 | |||
237 | async function listAccountRatings (req: express.Request, res: express.Response) { | ||
238 | const account = res.locals.account | ||
239 | |||
240 | const resultList = await AccountVideoRateModel.listByAccountForApi({ | ||
241 | accountId: account.id, | ||
242 | start: req.query.start, | ||
243 | count: req.query.count, | ||
244 | sort: req.query.sort, | ||
245 | type: req.query.rating | ||
246 | }) | ||
247 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
248 | } | ||
249 | |||
250 | async function listAccountFollowers (req: express.Request, res: express.Response) { | ||
251 | const account = res.locals.account | ||
252 | |||
253 | const channels = await VideoChannelModel.listAllByAccount(account.id) | ||
254 | const actorIds = [ account.actorId ].concat(channels.map(c => c.actorId)) | ||
255 | |||
256 | const resultList = await ActorFollowModel.listFollowersForApi({ | ||
257 | actorIds, | ||
258 | start: req.query.start, | ||
259 | count: req.query.count, | ||
260 | sort: req.query.sort, | ||
261 | search: req.query.search, | ||
262 | state: 'accepted' | ||
263 | }) | ||
264 | |||
265 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
266 | } | ||