aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/api/users/index.ts (renamed from server/controllers/api/users.ts)224
-rw-r--r--server/controllers/api/users/me.ts215
2 files changed, 231 insertions, 208 deletions
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users/index.ts
index 543b20baa..105244ddd 100644
--- a/server/controllers/api/users.ts
+++ b/server/controllers/api/users/index.ts
@@ -1,14 +1,12 @@
1import * as express from 'express' 1import * as express from 'express'
2import 'multer'
3import * as RateLimit from 'express-rate-limit' 2import * as RateLimit from 'express-rate-limit'
4import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' 3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared'
5import { logger } from '../../helpers/logger' 4import { logger } from '../../../helpers/logger'
6import { getFormattedObjects } from '../../helpers/utils' 5import { getFormattedObjects } from '../../../helpers/utils'
7import { CONFIG, IMAGE_MIMETYPE_EXT, RATES_LIMIT, sequelizeTypescript } from '../../initializers' 6import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers'
8import { sendUpdateActor } from '../../lib/activitypub/send' 7import { Emailer } from '../../../lib/emailer'
9import { Emailer } from '../../lib/emailer' 8import { Redis } from '../../../lib/redis'
10import { Redis } from '../../lib/redis' 9import { createUserAccountAndChannel } from '../../../lib/user'
11import { createUserAccountAndChannel } from '../../lib/user'
12import { 10import {
13 asyncMiddleware, 11 asyncMiddleware,
14 asyncRetryTransactionMiddleware, 12 asyncRetryTransactionMiddleware,
@@ -25,33 +23,17 @@ import {
25 usersRegisterValidator, 23 usersRegisterValidator,
26 usersRemoveValidator, 24 usersRemoveValidator,
27 usersSortValidator, 25 usersSortValidator,
28 usersUpdateMeValidator, 26 usersUpdateValidator
29 usersUpdateValidator, 27} from '../../../middlewares'
30 usersVideoRatingValidator 28import { usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator } from '../../../middlewares/validators'
31} from '../../middlewares' 29import { UserModel } from '../../../models/account/user'
32import { 30import { OAuthTokenModel } from '../../../models/oauth/oauth-token'
33 deleteMeValidator, 31import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
34 usersAskResetPasswordValidator, 32import { videosRouter } from '../videos'
35 usersBlockingValidator, 33import { meRouter } from './me'
36 usersResetPasswordValidator,
37 videoImportsSortValidator,
38 videosSortValidator
39} from '../../middlewares/validators'
40import { AccountVideoRateModel } from '../../models/account/account-video-rate'
41import { UserModel } from '../../models/account/user'
42import { OAuthTokenModel } from '../../models/oauth/oauth-token'
43import { VideoModel } from '../../models/video/video'
44import { VideoSortField } from '../../../client/src/app/shared/video/sort-field.type'
45import { createReqFiles } from '../../helpers/express-utils'
46import { UserVideoQuota } from '../../../shared/models/users/user-video-quota.model'
47import { updateAvatarValidator } from '../../middlewares/validators/avatar'
48import { updateActorAvatarFile } from '../../lib/avatar'
49import { auditLoggerFactory, UserAuditView } from '../../helpers/audit-logger'
50import { VideoImportModel } from '../../models/video/video-import'
51 34
52const auditLogger = auditLoggerFactory('users') 35const auditLogger = auditLoggerFactory('users')
53 36
54const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
55const loginRateLimiter = new RateLimit({ 37const loginRateLimiter = new RateLimit({
56 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS, 38 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
57 max: RATES_LIMIT.LOGIN.MAX, 39 max: RATES_LIMIT.LOGIN.MAX,
@@ -59,45 +41,7 @@ const loginRateLimiter = new RateLimit({
59}) 41})
60 42
61const usersRouter = express.Router() 43const usersRouter = express.Router()
62 44videosRouter.use('/', meRouter)
63usersRouter.get('/me',
64 authenticate,
65 asyncMiddleware(getUserInformation)
66)
67usersRouter.delete('/me',
68 authenticate,
69 asyncMiddleware(deleteMeValidator),
70 asyncMiddleware(deleteMe)
71)
72
73usersRouter.get('/me/video-quota-used',
74 authenticate,
75 asyncMiddleware(getUserVideoQuotaUsed)
76)
77
78usersRouter.get('/me/videos/imports',
79 authenticate,
80 paginationValidator,
81 videoImportsSortValidator,
82 setDefaultSort,
83 setDefaultPagination,
84 asyncMiddleware(getUserVideoImports)
85)
86
87usersRouter.get('/me/videos',
88 authenticate,
89 paginationValidator,
90 videosSortValidator,
91 setDefaultSort,
92 setDefaultPagination,
93 asyncMiddleware(getUserVideos)
94)
95
96usersRouter.get('/me/videos/:videoId/rating',
97 authenticate,
98 asyncMiddleware(usersVideoRatingValidator),
99 asyncMiddleware(getUserVideoRating)
100)
101 45
102usersRouter.get('/', 46usersRouter.get('/',
103 authenticate, 47 authenticate,
@@ -143,19 +87,6 @@ usersRouter.post('/register',
143 asyncRetryTransactionMiddleware(registerUser) 87 asyncRetryTransactionMiddleware(registerUser)
144) 88)
145 89
146usersRouter.put('/me',
147 authenticate,
148 usersUpdateMeValidator,
149 asyncMiddleware(updateMe)
150)
151
152usersRouter.post('/me/avatar/pick',
153 authenticate,
154 reqAvatarFile,
155 updateAvatarValidator,
156 asyncMiddleware(updateMyAvatar)
157)
158
159usersRouter.put('/:id', 90usersRouter.put('/:id',
160 authenticate, 91 authenticate,
161 ensureUserHasRight(UserRight.MANAGE_USERS), 92 ensureUserHasRight(UserRight.MANAGE_USERS),
@@ -195,36 +126,6 @@ export {
195 126
196// --------------------------------------------------------------------------- 127// ---------------------------------------------------------------------------
197 128
198async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
199 const user = res.locals.oauth.token.User as UserModel
200 const resultList = await VideoModel.listUserVideosForApi(
201 user.Account.id,
202 req.query.start as number,
203 req.query.count as number,
204 req.query.sort as VideoSortField
205 )
206
207 const additionalAttributes = {
208 waitTranscoding: true,
209 state: true,
210 scheduledUpdate: true,
211 blacklistInfo: true
212 }
213 return res.json(getFormattedObjects(resultList.data, resultList.total, { additionalAttributes }))
214}
215
216async function getUserVideoImports (req: express.Request, res: express.Response, next: express.NextFunction) {
217 const user = res.locals.oauth.token.User as UserModel
218 const resultList = await VideoImportModel.listUserVideoImportsForApi(
219 user.id,
220 req.query.start as number,
221 req.query.count as number,
222 req.query.sort
223 )
224
225 return res.json(getFormattedObjects(resultList.data, resultList.total))
226}
227
228async function createUser (req: express.Request, res: express.Response) { 129async function createUser (req: express.Request, res: express.Response) {
229 const body: UserCreate = req.body 130 const body: UserCreate = req.body
230 const userToCreate = new UserModel({ 131 const userToCreate = new UserModel({
@@ -274,24 +175,6 @@ async function registerUser (req: express.Request, res: express.Response) {
274 return res.type('json').status(204).end() 175 return res.type('json').status(204).end()
275} 176}
276 177
277async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
278 // We did not load channels in res.locals.user
279 const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
280
281 return res.json(user.toFormattedJSON())
282}
283
284async function getUserVideoQuotaUsed (req: express.Request, res: express.Response, next: express.NextFunction) {
285 // We did not load channels in res.locals.user
286 const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
287 const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
288
289 const data: UserVideoQuota = {
290 videoQuotaUsed
291 }
292 return res.json(data)
293}
294
295async function unblockUser (req: express.Request, res: express.Response, next: express.NextFunction) { 178async function unblockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
296 const user: UserModel = res.locals.user 179 const user: UserModel = res.locals.user
297 180
@@ -313,36 +196,12 @@ function getUser (req: express.Request, res: express.Response, next: express.Nex
313 return res.json((res.locals.user as UserModel).toFormattedJSON()) 196 return res.json((res.locals.user as UserModel).toFormattedJSON())
314} 197}
315 198
316async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
317 const videoId = +req.params.videoId
318 const accountId = +res.locals.oauth.token.User.Account.id
319
320 const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null)
321 const rating = ratingObj ? ratingObj.type : 'none'
322
323 const json: FormattedUserVideoRate = {
324 videoId,
325 rating
326 }
327 res.json(json)
328}
329
330async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { 199async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
331 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort) 200 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort)
332 201
333 return res.json(getFormattedObjects(resultList.data, resultList.total)) 202 return res.json(getFormattedObjects(resultList.data, resultList.total))
334} 203}
335 204
336async function deleteMe (req: express.Request, res: express.Response) {
337 const user: UserModel = res.locals.oauth.token.User
338
339 await user.destroy()
340
341 auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
342
343 return res.sendStatus(204)
344}
345
346async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { 205async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
347 const user: UserModel = res.locals.user 206 const user: UserModel = res.locals.user
348 207
@@ -353,57 +212,6 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
353 return res.sendStatus(204) 212 return res.sendStatus(204)
354} 213}
355 214
356async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
357 const body: UserUpdateMe = req.body
358
359 const user: UserModel = res.locals.oauth.token.user
360 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
361
362 if (body.password !== undefined) user.password = body.password
363 if (body.email !== undefined) user.email = body.email
364 if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy
365 if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
366
367 await sequelizeTypescript.transaction(async t => {
368 await user.save({ transaction: t })
369
370 if (body.displayName !== undefined) user.Account.name = body.displayName
371 if (body.description !== undefined) user.Account.description = body.description
372 await user.Account.save({ transaction: t })
373
374 await sendUpdateActor(user.Account, t)
375
376 auditLogger.update(
377 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
378 new UserAuditView(user.toFormattedJSON()),
379 oldUserAuditView
380 )
381 })
382
383 return res.sendStatus(204)
384}
385
386async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
387 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
388 const user: UserModel = res.locals.oauth.token.user
389 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
390 const account = user.Account
391
392 const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account)
393
394 auditLogger.update(
395 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
396 new UserAuditView(user.toFormattedJSON()),
397 oldUserAuditView
398 )
399
400 return res
401 .json({
402 avatar: avatar.toFormattedJSON()
403 })
404 .end()
405}
406
407async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { 215async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
408 const body: UserUpdate = req.body 216 const body: UserUpdate = req.body
409 const userToUpdate = res.locals.user as UserModel 217 const userToUpdate = res.locals.user as UserModel
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
new file mode 100644
index 000000000..1e096a35d
--- /dev/null
+++ b/server/controllers/api/users/me.ts
@@ -0,0 +1,215 @@
1import * as express from 'express'
2import 'multer'
3import { UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../../shared'
4import { getFormattedObjects } from '../../../helpers/utils'
5import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers'
6import { sendUpdateActor } from '../../../lib/activitypub/send'
7import {
8 asyncMiddleware,
9 authenticate,
10 paginationValidator,
11 setDefaultPagination,
12 setDefaultSort,
13 usersUpdateMeValidator,
14 usersVideoRatingValidator
15} from '../../../middlewares'
16import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators'
17import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
18import { UserModel } from '../../../models/account/user'
19import { VideoModel } from '../../../models/video/video'
20import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type'
21import { createReqFiles } from '../../../helpers/express-utils'
22import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model'
23import { updateAvatarValidator } from '../../../middlewares/validators/avatar'
24import { updateActorAvatarFile } from '../../../lib/avatar'
25import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
26import { VideoImportModel } from '../../../models/video/video-import'
27
28const auditLogger = auditLoggerFactory('users-me')
29
30const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
31
32const meRouter = express.Router()
33
34meRouter.get('/me',
35 authenticate,
36 asyncMiddleware(getUserInformation)
37)
38meRouter.delete('/me',
39 authenticate,
40 asyncMiddleware(deleteMeValidator),
41 asyncMiddleware(deleteMe)
42)
43
44meRouter.get('/me/video-quota-used',
45 authenticate,
46 asyncMiddleware(getUserVideoQuotaUsed)
47)
48
49meRouter.get('/me/videos/imports',
50 authenticate,
51 paginationValidator,
52 videoImportsSortValidator,
53 setDefaultSort,
54 setDefaultPagination,
55 asyncMiddleware(getUserVideoImports)
56)
57
58meRouter.get('/me/videos',
59 authenticate,
60 paginationValidator,
61 videosSortValidator,
62 setDefaultSort,
63 setDefaultPagination,
64 asyncMiddleware(getUserVideos)
65)
66
67meRouter.get('/me/videos/:videoId/rating',
68 authenticate,
69 asyncMiddleware(usersVideoRatingValidator),
70 asyncMiddleware(getUserVideoRating)
71)
72
73meRouter.put('/me',
74 authenticate,
75 usersUpdateMeValidator,
76 asyncMiddleware(updateMe)
77)
78
79meRouter.post('/me/avatar/pick',
80 authenticate,
81 reqAvatarFile,
82 updateAvatarValidator,
83 asyncMiddleware(updateMyAvatar)
84)
85
86// ---------------------------------------------------------------------------
87
88export {
89 meRouter
90}
91
92// ---------------------------------------------------------------------------
93
94async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
95 const user = res.locals.oauth.token.User as UserModel
96 const resultList = await VideoModel.listUserVideosForApi(
97 user.Account.id,
98 req.query.start as number,
99 req.query.count as number,
100 req.query.sort as VideoSortField
101 )
102
103 const additionalAttributes = {
104 waitTranscoding: true,
105 state: true,
106 scheduledUpdate: true,
107 blacklistInfo: true
108 }
109 return res.json(getFormattedObjects(resultList.data, resultList.total, { additionalAttributes }))
110}
111
112async function getUserVideoImports (req: express.Request, res: express.Response, next: express.NextFunction) {
113 const user = res.locals.oauth.token.User as UserModel
114 const resultList = await VideoImportModel.listUserVideoImportsForApi(
115 user.id,
116 req.query.start as number,
117 req.query.count as number,
118 req.query.sort
119 )
120
121 return res.json(getFormattedObjects(resultList.data, resultList.total))
122}
123
124async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
125 // We did not load channels in res.locals.user
126 const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
127
128 return res.json(user.toFormattedJSON())
129}
130
131async function getUserVideoQuotaUsed (req: express.Request, res: express.Response, next: express.NextFunction) {
132 // We did not load channels in res.locals.user
133 const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
134 const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
135
136 const data: UserVideoQuota = {
137 videoQuotaUsed
138 }
139 return res.json(data)
140}
141
142async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
143 const videoId = +req.params.videoId
144 const accountId = +res.locals.oauth.token.User.Account.id
145
146 const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null)
147 const rating = ratingObj ? ratingObj.type : 'none'
148
149 const json: FormattedUserVideoRate = {
150 videoId,
151 rating
152 }
153 res.json(json)
154}
155
156async function deleteMe (req: express.Request, res: express.Response) {
157 const user: UserModel = res.locals.oauth.token.User
158
159 await user.destroy()
160
161 auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
162
163 return res.sendStatus(204)
164}
165
166async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
167 const body: UserUpdateMe = req.body
168
169 const user: UserModel = res.locals.oauth.token.user
170 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
171
172 if (body.password !== undefined) user.password = body.password
173 if (body.email !== undefined) user.email = body.email
174 if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy
175 if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
176
177 await sequelizeTypescript.transaction(async t => {
178 await user.save({ transaction: t })
179
180 if (body.displayName !== undefined) user.Account.name = body.displayName
181 if (body.description !== undefined) user.Account.description = body.description
182 await user.Account.save({ transaction: t })
183
184 await sendUpdateActor(user.Account, t)
185
186 auditLogger.update(
187 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
188 new UserAuditView(user.toFormattedJSON()),
189 oldUserAuditView
190 )
191 })
192
193 return res.sendStatus(204)
194}
195
196async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
197 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
198 const user: UserModel = res.locals.oauth.token.user
199 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
200 const account = user.Account
201
202 const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account)
203
204 auditLogger.update(
205 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
206 new UserAuditView(user.toFormattedJSON()),
207 oldUserAuditView
208 )
209
210 return res
211 .json({
212 avatar: avatar.toFormattedJSON()
213 })
214 .end()
215}