]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/users/me.ts
Allow user to search through their watch history (#3576)
[github/Chocobozzz/PeerTube.git] / server / controllers / api / users / me.ts
CommitLineData
d03cd8bb 1import 'multer'
67ed6552 2import * as express from 'express'
2dbc170d 3import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '@server/helpers/audit-logger'
67ed6552 4import { UserUpdateMe, UserVideoRate as FormattedUserVideoRate, VideoSortField } from '../../../../shared'
2dbc170d 5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
67ed6552
C
6import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model'
7import { createReqFiles } from '../../../helpers/express-utils'
d03cd8bb 8import { getFormattedObjects } from '../../../helpers/utils'
67ed6552 9import { CONFIG } from '../../../initializers/config'
74dc3bca 10import { MIMETYPES } from '../../../initializers/constants'
67ed6552 11import { sequelizeTypescript } from '../../../initializers/database'
d03cd8bb 12import { sendUpdateActor } from '../../../lib/activitypub/send'
1ea7da81 13import { deleteActorAvatarFile, updateActorAvatarFile } from '../../../lib/avatar'
fb719404 14import { getOriginalVideoFileTotalDailyFromUser, getOriginalVideoFileTotalFromUser, sendVerifyUserEmail } from '../../../lib/user'
d03cd8bb 15import {
993cef4b
C
16 asyncMiddleware,
17 asyncRetryTransactionMiddleware,
d03cd8bb
C
18 authenticate,
19 paginationValidator,
20 setDefaultPagination,
21 setDefaultSort,
8054669f 22 setDefaultVideosSort,
d03cd8bb
C
23 usersUpdateMeValidator,
24 usersVideoRatingValidator
25} from '../../../middlewares'
cf405589 26import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators'
67ed6552
C
27import { updateAvatarValidator } from '../../../middlewares/validators/avatar'
28import { AccountModel } from '../../../models/account/account'
d03cd8bb
C
29import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
30import { UserModel } from '../../../models/account/user'
31import { VideoModel } from '../../../models/video/video'
d03cd8bb 32import { VideoImportModel } from '../../../models/video/video-import'
2dbc170d
C
33
34const auditLogger = auditLoggerFactory('users')
d03cd8bb 35
14e2014a 36const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR })
d03cd8bb
C
37
38const meRouter = express.Router()
39
40meRouter.get('/me',
41 authenticate,
42 asyncMiddleware(getUserInformation)
43)
44meRouter.delete('/me',
45 authenticate,
a1587156 46 deleteMeValidator,
d03cd8bb
C
47 asyncMiddleware(deleteMe)
48)
49
50meRouter.get('/me/video-quota-used',
51 authenticate,
52 asyncMiddleware(getUserVideoQuotaUsed)
53)
54
55meRouter.get('/me/videos/imports',
56 authenticate,
57 paginationValidator,
58 videoImportsSortValidator,
59 setDefaultSort,
60 setDefaultPagination,
61 asyncMiddleware(getUserVideoImports)
62)
63
64meRouter.get('/me/videos',
65 authenticate,
66 paginationValidator,
67 videosSortValidator,
8054669f 68 setDefaultVideosSort,
d03cd8bb
C
69 setDefaultPagination,
70 asyncMiddleware(getUserVideos)
71)
72
73meRouter.get('/me/videos/:videoId/rating',
74 authenticate,
75 asyncMiddleware(usersVideoRatingValidator),
76 asyncMiddleware(getUserVideoRating)
77)
78
79meRouter.put('/me',
80 authenticate,
a890d1e0 81 asyncMiddleware(usersUpdateMeValidator),
176e2114 82 asyncRetryTransactionMiddleware(updateMe)
d03cd8bb
C
83)
84
85meRouter.post('/me/avatar/pick',
86 authenticate,
87 reqAvatarFile,
88 updateAvatarValidator,
176e2114 89 asyncRetryTransactionMiddleware(updateMyAvatar)
d03cd8bb
C
90)
91
1ea7da81
RK
92meRouter.delete('/me/avatar',
93 authenticate,
94 asyncRetryTransactionMiddleware(deleteMyAvatar)
95)
96
d03cd8bb
C
97// ---------------------------------------------------------------------------
98
99export {
100 meRouter
101}
102
103// ---------------------------------------------------------------------------
104
dae86118
C
105async function getUserVideos (req: express.Request, res: express.Response) {
106 const user = res.locals.oauth.token.User
d03cd8bb
C
107 const resultList = await VideoModel.listUserVideosForApi(
108 user.Account.id,
109 req.query.start as number,
110 req.query.count as number,
bf64ed41
RK
111 req.query.sort as VideoSortField,
112 req.query.search as string
d03cd8bb
C
113 )
114
115 const additionalAttributes = {
116 waitTranscoding: true,
117 state: true,
118 scheduledUpdate: true,
119 blacklistInfo: true
120 }
121 return res.json(getFormattedObjects(resultList.data, resultList.total, { additionalAttributes }))
122}
123
dae86118
C
124async function getUserVideoImports (req: express.Request, res: express.Response) {
125 const user = res.locals.oauth.token.User
d03cd8bb
C
126 const resultList = await VideoImportModel.listUserVideoImportsForApi(
127 user.id,
128 req.query.start as number,
129 req.query.count as number,
130 req.query.sort
131 )
132
133 return res.json(getFormattedObjects(resultList.data, resultList.total))
134}
135
dae86118 136async function getUserInformation (req: express.Request, res: express.Response) {
d03cd8bb 137 // We did not load channels in res.locals.user
1acb9475 138 const user = await UserModel.loadForMeAPI(res.locals.oauth.token.user.id)
d03cd8bb 139
ac0868bc 140 return res.json(user.toMeFormattedJSON())
d03cd8bb
C
141}
142
dae86118 143async function getUserVideoQuotaUsed (req: express.Request, res: express.Response) {
ac0868bc 144 const user = res.locals.oauth.token.user
fb719404
C
145 const videoQuotaUsed = await getOriginalVideoFileTotalFromUser(user)
146 const videoQuotaUsedDaily = await getOriginalVideoFileTotalDailyFromUser(user)
d03cd8bb
C
147
148 const data: UserVideoQuota = {
bee0abff
FA
149 videoQuotaUsed,
150 videoQuotaUsedDaily
d03cd8bb
C
151 }
152 return res.json(data)
153}
154
dae86118 155async function getUserVideoRating (req: express.Request, res: express.Response) {
453e83ea 156 const videoId = res.locals.videoId.id
d03cd8bb
C
157 const accountId = +res.locals.oauth.token.User.Account.id
158
159 const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null)
160 const rating = ratingObj ? ratingObj.type : 'none'
161
162 const json: FormattedUserVideoRate = {
163 videoId,
164 rating
165 }
06a05d5f 166 return res.json(json)
d03cd8bb
C
167}
168
169async function deleteMe (req: express.Request, res: express.Response) {
2dbc170d
C
170 const user = await UserModel.loadByIdWithChannels(res.locals.oauth.token.User.id)
171
172 auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
d03cd8bb
C
173
174 await user.destroy()
175
2d53be02 176 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
d03cd8bb
C
177}
178
b426edd4 179async function updateMe (req: express.Request, res: express.Response) {
d03cd8bb 180 const body: UserUpdateMe = req.body
d1ab89de 181 let sendVerificationEmail = false
d03cd8bb 182
dae86118 183 const user = res.locals.oauth.token.user
d03cd8bb
C
184
185 if (body.password !== undefined) user.password = body.password
d03cd8bb 186 if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy
ed638e53 187 if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled
d03cd8bb 188 if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
6aa54148 189 if (body.autoPlayNextVideo !== undefined) user.autoPlayNextVideo = body.autoPlayNextVideo
bee29df8 190 if (body.autoPlayNextVideoPlaylist !== undefined) user.autoPlayNextVideoPlaylist = body.autoPlayNextVideoPlaylist
8b9a525a 191 if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled
3caf77d3 192 if (body.videoLanguages !== undefined) user.videoLanguages = body.videoLanguages
7cd4d2ba 193 if (body.theme !== undefined) user.theme = body.theme
43d0ea7f
C
194 if (body.noInstanceConfigWarningModal !== undefined) user.noInstanceConfigWarningModal = body.noInstanceConfigWarningModal
195 if (body.noWelcomeModal !== undefined) user.noWelcomeModal = body.noWelcomeModal
d03cd8bb 196
d1ab89de
C
197 if (body.email !== undefined) {
198 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
199 user.pendingEmail = body.email
200 sendVerificationEmail = true
201 } else {
202 user.email = body.email
203 }
204 }
205
589d9f55
C
206 await sequelizeTypescript.transaction(async t => {
207 await user.save({ transaction: t })
91411dba 208
589d9f55
C
209 if (body.displayName !== undefined || body.description !== undefined) {
210 const userAccount = await AccountModel.load(user.Account.id, t)
d03cd8bb 211
43d0ea7f
C
212 if (body.displayName !== undefined) userAccount.name = body.displayName
213 if (body.description !== undefined) userAccount.description = body.description
214 await userAccount.save({ transaction: t })
d03cd8bb 215
43d0ea7f 216 await sendUpdateActor(userAccount, t)
589d9f55
C
217 }
218 })
d03cd8bb 219
d1ab89de
C
220 if (sendVerificationEmail === true) {
221 await sendVerifyUserEmail(user, true)
222 }
223
2d53be02 224 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
d03cd8bb
C
225}
226
6040f87d 227async function updateMyAvatar (req: express.Request, res: express.Response) {
a1587156 228 const avatarPhysicalFile = req.files['avatarfile'][0]
dae86118 229 const user = res.locals.oauth.token.user
d03cd8bb 230
91411dba 231 const userAccount = await AccountModel.load(user.Account.id)
d03cd8bb 232
1ea7da81 233 const avatar = await updateActorAvatarFile(userAccount, avatarPhysicalFile)
91411dba 234
06a05d5f 235 return res.json({ avatar: avatar.toFormattedJSON() })
d03cd8bb 236}
1ea7da81
RK
237
238async function deleteMyAvatar (req: express.Request, res: express.Response) {
239 const user = res.locals.oauth.token.user
240
241 const userAccount = await AccountModel.load(user.Account.id)
242 await deleteActorAvatarFile(userAccount)
243
244 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
245}