diff options
-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.ts | 215 |
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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import 'multer' | ||
3 | import * as RateLimit from 'express-rate-limit' | 2 | import * as RateLimit from 'express-rate-limit' |
4 | import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' | 3 | import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared' |
5 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
6 | import { getFormattedObjects } from '../../helpers/utils' | 5 | import { getFormattedObjects } from '../../../helpers/utils' |
7 | import { CONFIG, IMAGE_MIMETYPE_EXT, RATES_LIMIT, sequelizeTypescript } from '../../initializers' | 6 | import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers' |
8 | import { sendUpdateActor } from '../../lib/activitypub/send' | 7 | import { Emailer } from '../../../lib/emailer' |
9 | import { Emailer } from '../../lib/emailer' | 8 | import { Redis } from '../../../lib/redis' |
10 | import { Redis } from '../../lib/redis' | 9 | import { createUserAccountAndChannel } from '../../../lib/user' |
11 | import { createUserAccountAndChannel } from '../../lib/user' | ||
12 | import { | 10 | import { |
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 | 28 | import { usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator } from '../../../middlewares/validators' |
31 | } from '../../middlewares' | 29 | import { UserModel } from '../../../models/account/user' |
32 | import { | 30 | import { OAuthTokenModel } from '../../../models/oauth/oauth-token' |
33 | deleteMeValidator, | 31 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' |
34 | usersAskResetPasswordValidator, | 32 | import { videosRouter } from '../videos' |
35 | usersBlockingValidator, | 33 | import { meRouter } from './me' |
36 | usersResetPasswordValidator, | ||
37 | videoImportsSortValidator, | ||
38 | videosSortValidator | ||
39 | } from '../../middlewares/validators' | ||
40 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | ||
41 | import { UserModel } from '../../models/account/user' | ||
42 | import { OAuthTokenModel } from '../../models/oauth/oauth-token' | ||
43 | import { VideoModel } from '../../models/video/video' | ||
44 | import { VideoSortField } from '../../../client/src/app/shared/video/sort-field.type' | ||
45 | import { createReqFiles } from '../../helpers/express-utils' | ||
46 | import { UserVideoQuota } from '../../../shared/models/users/user-video-quota.model' | ||
47 | import { updateAvatarValidator } from '../../middlewares/validators/avatar' | ||
48 | import { updateActorAvatarFile } from '../../lib/avatar' | ||
49 | import { auditLoggerFactory, UserAuditView } from '../../helpers/audit-logger' | ||
50 | import { VideoImportModel } from '../../models/video/video-import' | ||
51 | 34 | ||
52 | const auditLogger = auditLoggerFactory('users') | 35 | const auditLogger = auditLoggerFactory('users') |
53 | 36 | ||
54 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) | ||
55 | const loginRateLimiter = new RateLimit({ | 37 | const 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 | ||
61 | const usersRouter = express.Router() | 43 | const usersRouter = express.Router() |
62 | 44 | videosRouter.use('/', meRouter) | |
63 | usersRouter.get('/me', | ||
64 | authenticate, | ||
65 | asyncMiddleware(getUserInformation) | ||
66 | ) | ||
67 | usersRouter.delete('/me', | ||
68 | authenticate, | ||
69 | asyncMiddleware(deleteMeValidator), | ||
70 | asyncMiddleware(deleteMe) | ||
71 | ) | ||
72 | |||
73 | usersRouter.get('/me/video-quota-used', | ||
74 | authenticate, | ||
75 | asyncMiddleware(getUserVideoQuotaUsed) | ||
76 | ) | ||
77 | |||
78 | usersRouter.get('/me/videos/imports', | ||
79 | authenticate, | ||
80 | paginationValidator, | ||
81 | videoImportsSortValidator, | ||
82 | setDefaultSort, | ||
83 | setDefaultPagination, | ||
84 | asyncMiddleware(getUserVideoImports) | ||
85 | ) | ||
86 | |||
87 | usersRouter.get('/me/videos', | ||
88 | authenticate, | ||
89 | paginationValidator, | ||
90 | videosSortValidator, | ||
91 | setDefaultSort, | ||
92 | setDefaultPagination, | ||
93 | asyncMiddleware(getUserVideos) | ||
94 | ) | ||
95 | |||
96 | usersRouter.get('/me/videos/:videoId/rating', | ||
97 | authenticate, | ||
98 | asyncMiddleware(usersVideoRatingValidator), | ||
99 | asyncMiddleware(getUserVideoRating) | ||
100 | ) | ||
101 | 45 | ||
102 | usersRouter.get('/', | 46 | usersRouter.get('/', |
103 | authenticate, | 47 | authenticate, |
@@ -143,19 +87,6 @@ usersRouter.post('/register', | |||
143 | asyncRetryTransactionMiddleware(registerUser) | 87 | asyncRetryTransactionMiddleware(registerUser) |
144 | ) | 88 | ) |
145 | 89 | ||
146 | usersRouter.put('/me', | ||
147 | authenticate, | ||
148 | usersUpdateMeValidator, | ||
149 | asyncMiddleware(updateMe) | ||
150 | ) | ||
151 | |||
152 | usersRouter.post('/me/avatar/pick', | ||
153 | authenticate, | ||
154 | reqAvatarFile, | ||
155 | updateAvatarValidator, | ||
156 | asyncMiddleware(updateMyAvatar) | ||
157 | ) | ||
158 | |||
159 | usersRouter.put('/:id', | 90 | usersRouter.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 | ||
198 | async 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 | |||
216 | async 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 | |||
228 | async function createUser (req: express.Request, res: express.Response) { | 129 | async 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 | ||
277 | async 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 | |||
284 | async 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 | |||
295 | async function unblockUser (req: express.Request, res: express.Response, next: express.NextFunction) { | 178 | async 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 | ||
316 | async 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 | |||
330 | async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { | 199 | async 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 | ||
336 | async 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 | |||
346 | async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { | 205 | async 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 | ||
356 | async 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 | |||
386 | async 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 | |||
407 | async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { | 215 | async 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 @@ | |||
1 | import * as express from 'express' | ||
2 | import 'multer' | ||
3 | import { UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../../shared' | ||
4 | import { getFormattedObjects } from '../../../helpers/utils' | ||
5 | import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers' | ||
6 | import { sendUpdateActor } from '../../../lib/activitypub/send' | ||
7 | import { | ||
8 | asyncMiddleware, | ||
9 | authenticate, | ||
10 | paginationValidator, | ||
11 | setDefaultPagination, | ||
12 | setDefaultSort, | ||
13 | usersUpdateMeValidator, | ||
14 | usersVideoRatingValidator | ||
15 | } from '../../../middlewares' | ||
16 | import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators' | ||
17 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | ||
18 | import { UserModel } from '../../../models/account/user' | ||
19 | import { VideoModel } from '../../../models/video/video' | ||
20 | import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type' | ||
21 | import { createReqFiles } from '../../../helpers/express-utils' | ||
22 | import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' | ||
23 | import { updateAvatarValidator } from '../../../middlewares/validators/avatar' | ||
24 | import { updateActorAvatarFile } from '../../../lib/avatar' | ||
25 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' | ||
26 | import { VideoImportModel } from '../../../models/video/video-import' | ||
27 | |||
28 | const auditLogger = auditLoggerFactory('users-me') | ||
29 | |||
30 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) | ||
31 | |||
32 | const meRouter = express.Router() | ||
33 | |||
34 | meRouter.get('/me', | ||
35 | authenticate, | ||
36 | asyncMiddleware(getUserInformation) | ||
37 | ) | ||
38 | meRouter.delete('/me', | ||
39 | authenticate, | ||
40 | asyncMiddleware(deleteMeValidator), | ||
41 | asyncMiddleware(deleteMe) | ||
42 | ) | ||
43 | |||
44 | meRouter.get('/me/video-quota-used', | ||
45 | authenticate, | ||
46 | asyncMiddleware(getUserVideoQuotaUsed) | ||
47 | ) | ||
48 | |||
49 | meRouter.get('/me/videos/imports', | ||
50 | authenticate, | ||
51 | paginationValidator, | ||
52 | videoImportsSortValidator, | ||
53 | setDefaultSort, | ||
54 | setDefaultPagination, | ||
55 | asyncMiddleware(getUserVideoImports) | ||
56 | ) | ||
57 | |||
58 | meRouter.get('/me/videos', | ||
59 | authenticate, | ||
60 | paginationValidator, | ||
61 | videosSortValidator, | ||
62 | setDefaultSort, | ||
63 | setDefaultPagination, | ||
64 | asyncMiddleware(getUserVideos) | ||
65 | ) | ||
66 | |||
67 | meRouter.get('/me/videos/:videoId/rating', | ||
68 | authenticate, | ||
69 | asyncMiddleware(usersVideoRatingValidator), | ||
70 | asyncMiddleware(getUserVideoRating) | ||
71 | ) | ||
72 | |||
73 | meRouter.put('/me', | ||
74 | authenticate, | ||
75 | usersUpdateMeValidator, | ||
76 | asyncMiddleware(updateMe) | ||
77 | ) | ||
78 | |||
79 | meRouter.post('/me/avatar/pick', | ||
80 | authenticate, | ||
81 | reqAvatarFile, | ||
82 | updateAvatarValidator, | ||
83 | asyncMiddleware(updateMyAvatar) | ||
84 | ) | ||
85 | |||
86 | // --------------------------------------------------------------------------- | ||
87 | |||
88 | export { | ||
89 | meRouter | ||
90 | } | ||
91 | |||
92 | // --------------------------------------------------------------------------- | ||
93 | |||
94 | async 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 | |||
112 | async 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 | |||
124 | async 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 | |||
131 | async 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 | |||
142 | async 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 | |||
156 | async 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 | |||
166 | async 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 | |||
196 | async 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 | } | ||