]>
Commit | Line | Data |
---|---|---|
4d4e5cd4 | 1 | import * as express from 'express' |
c5911fd3 | 2 | import { extname, join } from 'path' |
e8e12200 | 3 | import * as sharp from 'sharp' |
c5911fd3 | 4 | import * as uuidv4 from 'uuid/v4' |
571389d4 | 5 | import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' |
4e8c8728 | 6 | import { unlinkPromise } from '../../helpers/core-utils' |
da854ddd C |
7 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
8 | import { logger } from '../../helpers/logger' | |
c5911fd3 | 9 | import { createReqFiles, getFormattedObjects } from '../../helpers/utils' |
e8e12200 | 10 | import { AVATAR_MIMETYPE_EXT, AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../../initializers' |
a5625b41 | 11 | import { updateActorAvatarInstance } from '../../lib/activitypub' |
265ba139 | 12 | import { sendUpdateUser } from '../../lib/activitypub/send' |
50d6de9c | 13 | import { createUserAccountAndChannel } from '../../lib/user' |
65fcc311 | 14 | import { |
da854ddd C |
15 | asyncMiddleware, authenticate, ensureUserHasRight, ensureUserRegistrationAllowed, paginationValidator, setPagination, setUsersSort, |
16 | setVideosSort, token, usersAddValidator, usersGetValidator, usersRegisterValidator, usersRemoveValidator, usersSortValidator, | |
17 | usersUpdateMeValidator, usersUpdateValidator, usersVideoRatingValidator | |
65fcc311 | 18 | } from '../../middlewares' |
c5911fd3 | 19 | import { usersUpdateMyAvatarValidator, videosSortValidator } from '../../middlewares/validators' |
3fd3ab2d C |
20 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
21 | import { UserModel } from '../../models/account/user' | |
22 | import { VideoModel } from '../../models/video/video' | |
65fcc311 | 23 | |
c5911fd3 C |
24 | const reqAvatarFile = createReqFiles('avatarfile', CONFIG.STORAGE.AVATARS_DIR, AVATAR_MIMETYPE_EXT) |
25 | ||
65fcc311 C |
26 | const usersRouter = express.Router() |
27 | ||
28 | usersRouter.get('/me', | |
29 | authenticate, | |
eb080476 | 30 | asyncMiddleware(getUserInformation) |
d38b8281 C |
31 | ) |
32 | ||
fd45e8f4 C |
33 | usersRouter.get('/me/videos', |
34 | authenticate, | |
35 | paginationValidator, | |
36 | videosSortValidator, | |
37 | setVideosSort, | |
38 | setPagination, | |
39 | asyncMiddleware(getUserVideos) | |
40 | ) | |
41 | ||
65fcc311 C |
42 | usersRouter.get('/me/videos/:videoId/rating', |
43 | authenticate, | |
a2431b7d | 44 | asyncMiddleware(usersVideoRatingValidator), |
eb080476 | 45 | asyncMiddleware(getUserVideoRating) |
d38b8281 | 46 | ) |
9bd26629 | 47 | |
65fcc311 | 48 | usersRouter.get('/', |
86d13ec2 C |
49 | authenticate, |
50 | ensureUserHasRight(UserRight.MANAGE_USERS), | |
65fcc311 C |
51 | paginationValidator, |
52 | usersSortValidator, | |
53 | setUsersSort, | |
54 | setPagination, | |
eb080476 | 55 | asyncMiddleware(listUsers) |
5c39adb7 C |
56 | ) |
57 | ||
8094a898 | 58 | usersRouter.get('/:id', |
a2431b7d | 59 | asyncMiddleware(usersGetValidator), |
8094a898 C |
60 | getUser |
61 | ) | |
62 | ||
65fcc311 C |
63 | usersRouter.post('/', |
64 | authenticate, | |
954605a8 | 65 | ensureUserHasRight(UserRight.MANAGE_USERS), |
a2431b7d C |
66 | asyncMiddleware(usersAddValidator), |
67 | asyncMiddleware(createUserRetryWrapper) | |
9bd26629 C |
68 | ) |
69 | ||
65fcc311 | 70 | usersRouter.post('/register', |
a2431b7d C |
71 | asyncMiddleware(ensureUserRegistrationAllowed), |
72 | asyncMiddleware(usersRegisterValidator), | |
47e0652b | 73 | asyncMiddleware(registerUserRetryWrapper) |
2c2e9092 C |
74 | ) |
75 | ||
8094a898 C |
76 | usersRouter.put('/me', |
77 | authenticate, | |
78 | usersUpdateMeValidator, | |
eb080476 | 79 | asyncMiddleware(updateMe) |
8094a898 C |
80 | ) |
81 | ||
c5911fd3 C |
82 | usersRouter.post('/me/avatar/pick', |
83 | authenticate, | |
84 | reqAvatarFile, | |
85 | usersUpdateMyAvatarValidator, | |
86 | asyncMiddleware(updateMyAvatar) | |
87 | ) | |
88 | ||
65fcc311 C |
89 | usersRouter.put('/:id', |
90 | authenticate, | |
954605a8 | 91 | ensureUserHasRight(UserRight.MANAGE_USERS), |
a2431b7d | 92 | asyncMiddleware(usersUpdateValidator), |
eb080476 | 93 | asyncMiddleware(updateUser) |
9bd26629 C |
94 | ) |
95 | ||
65fcc311 C |
96 | usersRouter.delete('/:id', |
97 | authenticate, | |
954605a8 | 98 | ensureUserHasRight(UserRight.MANAGE_USERS), |
a2431b7d | 99 | asyncMiddleware(usersRemoveValidator), |
eb080476 | 100 | asyncMiddleware(removeUser) |
9bd26629 | 101 | ) |
6606150c | 102 | |
65fcc311 | 103 | usersRouter.post('/token', token, success) |
9bd26629 | 104 | // TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route |
9457bf88 C |
105 | |
106 | // --------------------------------------------------------------------------- | |
107 | ||
65fcc311 C |
108 | export { |
109 | usersRouter | |
110 | } | |
9457bf88 C |
111 | |
112 | // --------------------------------------------------------------------------- | |
113 | ||
fd45e8f4 | 114 | async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
3fd3ab2d C |
115 | const user = res.locals.oauth.token.User as UserModel |
116 | const resultList = await VideoModel.listUserVideosForApi(user.id ,req.query.start, req.query.count, req.query.sort) | |
fd45e8f4 C |
117 | |
118 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | |
119 | } | |
120 | ||
eb080476 | 121 | async function createUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { |
72c7248b | 122 | const options = { |
47e0652b | 123 | arguments: [ req ], |
72c7248b C |
124 | errorMessage: 'Cannot insert the user with many retries.' |
125 | } | |
126 | ||
eb080476 C |
127 | await retryTransactionWrapper(createUser, options) |
128 | ||
129 | // TODO : include Location of the new user -> 201 | |
130 | return res.type('json').status(204).end() | |
72c7248b C |
131 | } |
132 | ||
47e0652b | 133 | async function createUser (req: express.Request) { |
4771e000 | 134 | const body: UserCreate = req.body |
3fd3ab2d | 135 | const user = new UserModel({ |
4771e000 C |
136 | username: body.username, |
137 | password: body.password, | |
138 | email: body.email, | |
1d49e1e2 | 139 | displayNSFW: false, |
7efe153b | 140 | autoPlayVideo: true, |
954605a8 | 141 | role: body.role, |
b0f9f39e | 142 | videoQuota: body.videoQuota |
9bd26629 C |
143 | }) |
144 | ||
38fa2065 | 145 | await createUserAccountAndChannel(user) |
eb080476 | 146 | |
38fa2065 | 147 | logger.info('User %s with its channel and account created.', body.username) |
9bd26629 C |
148 | } |
149 | ||
47e0652b C |
150 | async function registerUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { |
151 | const options = { | |
152 | arguments: [ req ], | |
153 | errorMessage: 'Cannot insert the user with many retries.' | |
154 | } | |
155 | ||
156 | await retryTransactionWrapper(registerUser, options) | |
157 | ||
158 | return res.type('json').status(204).end() | |
159 | } | |
160 | ||
161 | async function registerUser (req: express.Request) { | |
77a5501f C |
162 | const body: UserCreate = req.body |
163 | ||
3fd3ab2d | 164 | const user = new UserModel({ |
77a5501f C |
165 | username: body.username, |
166 | password: body.password, | |
167 | email: body.email, | |
168 | displayNSFW: false, | |
7efe153b | 169 | autoPlayVideo: true, |
954605a8 | 170 | role: UserRole.USER, |
77a5501f C |
171 | videoQuota: CONFIG.USER.VIDEO_QUOTA |
172 | }) | |
173 | ||
38fa2065 | 174 | await createUserAccountAndChannel(user) |
47e0652b C |
175 | |
176 | logger.info('User %s with its channel and account registered.', body.username) | |
77a5501f C |
177 | } |
178 | ||
eb080476 | 179 | async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) { |
fd45e8f4 | 180 | // We did not load channels in res.locals.user |
3fd3ab2d | 181 | const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username) |
eb080476 C |
182 | |
183 | return res.json(user.toFormattedJSON()) | |
99a64bfe C |
184 | } |
185 | ||
8094a898 | 186 | function getUser (req: express.Request, res: express.Response, next: express.NextFunction) { |
11474c3c | 187 | return res.json(res.locals.user.toFormattedJSON()) |
8094a898 C |
188 | } |
189 | ||
eb080476 | 190 | async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { |
0a6658fd | 191 | const videoId = +req.params.videoId |
571389d4 | 192 | const accountId = +res.locals.oauth.token.User.Account.id |
d38b8281 | 193 | |
3fd3ab2d | 194 | const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null) |
faab3a84 C |
195 | const rating = ratingObj ? ratingObj.type : 'none' |
196 | ||
197 | const json: FormattedUserVideoRate = { | |
198 | videoId, | |
199 | rating | |
200 | } | |
201 | res.json(json) | |
d38b8281 C |
202 | } |
203 | ||
eb080476 | 204 | async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { |
3fd3ab2d | 205 | const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort) |
eb080476 C |
206 | |
207 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | |
9bd26629 C |
208 | } |
209 | ||
eb080476 | 210 | async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { |
3fd3ab2d | 211 | const user = await UserModel.loadById(req.params.id) |
eb080476 C |
212 | |
213 | await user.destroy() | |
214 | ||
215 | return res.sendStatus(204) | |
9bd26629 C |
216 | } |
217 | ||
eb080476 | 218 | async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) { |
8094a898 | 219 | const body: UserUpdateMe = req.body |
4771e000 | 220 | |
eb080476 | 221 | const user = res.locals.oauth.token.user |
1d49e1e2 | 222 | |
eb080476 C |
223 | if (body.password !== undefined) user.password = body.password |
224 | if (body.email !== undefined) user.email = body.email | |
225 | if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW | |
7efe153b | 226 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo |
eb080476 C |
227 | |
228 | await user.save() | |
265ba139 | 229 | await sendUpdateUser(user, undefined) |
eb080476 | 230 | |
d412e80e | 231 | return res.sendStatus(204) |
9bd26629 C |
232 | } |
233 | ||
c5911fd3 C |
234 | async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) { |
235 | const avatarPhysicalFile = req.files['avatarfile'][0] | |
265ba139 C |
236 | const user = res.locals.oauth.token.user |
237 | const actor = user.Account.Actor | |
c5911fd3 C |
238 | |
239 | const avatarDir = CONFIG.STORAGE.AVATARS_DIR | |
240 | const source = join(avatarDir, avatarPhysicalFile.filename) | |
241 | const extension = extname(avatarPhysicalFile.filename) | |
242 | const avatarName = uuidv4() + extension | |
243 | const destination = join(avatarDir, avatarName) | |
244 | ||
e8e12200 C |
245 | await sharp(source) |
246 | .resize(AVATARS_SIZE.width, AVATARS_SIZE.height) | |
247 | .toFile(destination) | |
248 | ||
249 | await unlinkPromise(source) | |
c5911fd3 | 250 | |
a5625b41 | 251 | const avatar = await sequelizeTypescript.transaction(async t => { |
bb82394c C |
252 | const updatedActor = await updateActorAvatarInstance(actor, avatarName, t) |
253 | await updatedActor.save({ transaction: t }) | |
c5911fd3 | 254 | |
a5625b41 | 255 | await sendUpdateUser(user, t) |
c5911fd3 | 256 | |
bb82394c | 257 | return updatedActor.Avatar |
c5911fd3 C |
258 | }) |
259 | ||
260 | return res | |
261 | .json({ | |
262 | avatar: avatar.toFormattedJSON() | |
263 | }) | |
264 | .end() | |
265 | } | |
266 | ||
eb080476 | 267 | async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { |
8094a898 | 268 | const body: UserUpdate = req.body |
3fd3ab2d | 269 | const user = res.locals.user as UserModel |
8094a898 C |
270 | |
271 | if (body.email !== undefined) user.email = body.email | |
272 | if (body.videoQuota !== undefined) user.videoQuota = body.videoQuota | |
954605a8 | 273 | if (body.role !== undefined) user.role = body.role |
8094a898 | 274 | |
eb080476 C |
275 | await user.save() |
276 | ||
265ba139 C |
277 | // Don't need to send this update to followers, these attributes are not propagated |
278 | ||
eb080476 | 279 | return res.sendStatus(204) |
8094a898 C |
280 | } |
281 | ||
69818c93 | 282 | function success (req: express.Request, res: express.Response, next: express.NextFunction) { |
9457bf88 C |
283 | res.end() |
284 | } |