]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/core/users/user.service.ts
Remove unnecessary function
[github/Chocobozzz/PeerTube.git] / client / src / app / core / users / user.service.ts
CommitLineData
5c20a455
C
1import { SortMeta } from 'primeng/api'
2import { from, Observable, of } from 'rxjs'
a9bfa85d 3import { catchError, concatMap, first, map, shareReplay, tap, toArray } from 'rxjs/operators'
74d63469 4import { HttpClient, HttpParams } from '@angular/common/http'
63c4db6d 5import { Injectable } from '@angular/core'
5c20a455 6import { AuthService } from '@app/core/auth'
b4c3c51d 7import { getBytes } from '@root-helpers/bytes'
67ed6552 8import {
f4796856 9 ActorImage,
67ed6552
C
10 ResultList,
11 User as UserServerModel,
12 UserCreate,
13 UserRegister,
14 UserRole,
15 UserUpdate,
16 UserUpdateMe,
17 UserVideoQuota
18} from '@shared/models'
5c20a455 19import { environment } from '../../../environments/environment'
5c20a455 20import { RestExtractor, RestPagination, RestService } from '../rest'
a9bfa85d 21import { UserLocalStorageService } from './'
5c20a455 22import { User } from './user.model'
629d8d6f
C
23
24@Injectable()
e2a2d6c8 25export class UserService {
63c4db6d 26 static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/'
629d8d6f 27
d3217560 28 private userCache: { [ id: number ]: Observable<UserServerModel> } = {}
218b0874 29
bf80903f
C
30 private signupInThisSession = false
31
df98563e 32 constructor (
d592e0a9 33 private authHttp: HttpClient,
5c20a455 34 private authService: AuthService,
e724fa93
C
35 private restExtractor: RestExtractor,
36 private restService: RestService,
a9bfa85d 37 private userLocalStorageService: UserLocalStorageService
9df52d66 38 ) { }
629d8d6f 39
bf80903f
C
40 hasSignupInThisSession () {
41 return this.signupInThisSession
42 }
43
a890d1e0 44 changePassword (currentPassword: string, newPassword: string) {
8094a898
C
45 const url = UserService.BASE_USERS_URL + 'me'
46 const body: UserUpdateMe = {
a890d1e0 47 currentPassword,
629d8d6f 48 password: newPassword
df98563e 49 }
629d8d6f 50
de59c48f 51 return this.authHttp.put(url, body)
e8bffe96 52 .pipe(catchError(err => this.restExtractor.handleError(err)))
629d8d6f 53 }
af5e743b 54
0ba5f5ba
C
55 changeEmail (password: string, newEmail: string) {
56 const url = UserService.BASE_USERS_URL + 'me'
57 const body: UserUpdateMe = {
58 currentPassword: password,
59 email: newEmail
60 }
61
62 return this.authHttp.put(url, body)
e8bffe96 63 .pipe(catchError(err => this.restExtractor.handleError(err)))
0ba5f5ba
C
64 }
65
a9bfa85d
C
66 // ---------------------------------------------------------------------------
67
68 updateMyAnonymousProfile (profile: UserUpdateMe) {
69 this.userLocalStorageService.setUserInfo(profile)
70 }
71
72 listenAnonymousUpdate () {
73 return this.userLocalStorageService.listenUserInfoChange()
74 .pipe(map(() => this.getAnonymousUser()))
75 }
76
77 getAnonymousUser () {
78 return new User(this.userLocalStorageService.getUserInfo())
79 }
80
81 // ---------------------------------------------------------------------------
82
ed56ad11 83 updateMyProfile (profile: UserUpdateMe) {
8094a898 84 const url = UserService.BASE_USERS_URL + 'me'
af5e743b 85
ed56ad11 86 return this.authHttp.put(url, profile)
e8bffe96 87 .pipe(catchError(err => this.restExtractor.handleError(err)))
af5e743b 88 }
a184c71b 89
92b9d60c
C
90 deleteMe () {
91 const url = UserService.BASE_USERS_URL + 'me'
92
93 return this.authHttp.delete(url)
e8bffe96 94 .pipe(catchError(err => this.restExtractor.handleError(err)))
92b9d60c
C
95 }
96
c5911fd3
C
97 changeAvatar (avatarForm: FormData) {
98 const url = UserService.BASE_USERS_URL + 'me/avatar/pick'
99
f4796856 100 return this.authHttp.post<{ avatar: ActorImage }>(url, avatarForm)
e4f0e92e 101 .pipe(catchError(err => this.restExtractor.handleError(err)))
c5911fd3
C
102 }
103
1ea7da81
RK
104 deleteAvatar () {
105 const url = UserService.BASE_USERS_URL + 'me/avatar'
106
107 return this.authHttp.delete(url)
e8bffe96 108 .pipe(catchError(err => this.restExtractor.handleError(err)))
1ea7da81
RK
109 }
110
1d5342ab 111 signup (userCreate: UserRegister) {
d592e0a9 112 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
db400f44 113 .pipe(
bf80903f 114 tap(() => this.signupInThisSession = true),
e4f0e92e 115 catchError(err => this.restExtractor.handleError(err))
db400f44 116 )
a184c71b 117 }
c5911fd3 118
ce5496d6 119 getMyVideoQuotaUsed () {
bf64ed41 120 const url = UserService.BASE_USERS_URL + 'me/video-quota-used'
c5911fd3 121
5fcbd898 122 return this.authHttp.get<UserVideoQuota>(url)
e4f0e92e 123 .pipe(catchError(err => this.restExtractor.handleError(err)))
c5911fd3 124 }
ecb4e35f
C
125
126 askResetPassword (email: string) {
127 const url = UserService.BASE_USERS_URL + '/ask-reset-password'
128
129 return this.authHttp.post(url, { email })
e8bffe96 130 .pipe(catchError(err => this.restExtractor.handleError(err)))
ecb4e35f
C
131 }
132
133 resetPassword (userId: number, verificationString: string, password: string) {
134 const url = `${UserService.BASE_USERS_URL}/${userId}/reset-password`
135 const body = {
136 verificationString,
137 password
138 }
139
140 return this.authHttp.post(url, body)
e8bffe96 141 .pipe(catchError(res => this.restExtractor.handleError(res)))
ecb4e35f 142 }
d9eaee39 143
0ba5f5ba 144 verifyEmail (userId: number, verificationString: string, isPendingEmail: boolean) {
d9eaee39
JM
145 const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email`
146 const body = {
0ba5f5ba
C
147 verificationString,
148 isPendingEmail
d9eaee39
JM
149 }
150
151 return this.authHttp.post(url, body)
e8bffe96 152 .pipe(catchError(res => this.restExtractor.handleError(res)))
d9eaee39
JM
153 }
154
155 askSendVerifyEmail (email: string) {
156 const url = UserService.BASE_USERS_URL + '/ask-send-verify-email'
157
158 return this.authHttp.post(url, { email })
e8bffe96 159 .pipe(catchError(err => this.restExtractor.handleError(err)))
d9eaee39 160 }
74d63469
GR
161
162 autocomplete (search: string): Observable<string[]> {
163 const url = UserService.BASE_USERS_URL + 'autocomplete'
164 const params = new HttpParams().append('search', search)
165
166 return this.authHttp
167 .get<string[]>(url, { params })
168 .pipe(catchError(res => this.restExtractor.handleError(res)))
169 }
e724fa93 170
1f20622f
C
171 getNewUsername (oldDisplayName: string, newDisplayName: string, currentUsername: string) {
172 // Don't update display name, the user seems to have changed it
173 if (this.displayNameToUsername(oldDisplayName) !== currentUsername) return currentUsername
174
175 return this.displayNameToUsername(newDisplayName)
176 }
177
178 displayNameToUsername (displayName: string) {
179 if (!displayName) return ''
180
181 return displayName
182 .toLowerCase()
183 .replace(/\s/g, '_')
184 .replace(/[^a-z0-9_.]/g, '')
185 }
186
e724fa93
C
187 /* ###### Admin methods ###### */
188
189 addUser (userCreate: UserCreate) {
190 return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
e8bffe96 191 .pipe(catchError(err => this.restExtractor.handleError(err)))
e724fa93
C
192 }
193
194 updateUser (userId: number, userUpdate: UserUpdate) {
195 return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
e8bffe96 196 .pipe(catchError(err => this.restExtractor.handleError(err)))
e724fa93
C
197 }
198
d3217560 199 updateUsers (users: UserServerModel[], userUpdate: UserUpdate) {
fc2ec87a
JM
200 return from(users)
201 .pipe(
202 concatMap(u => this.authHttp.put(UserService.BASE_USERS_URL + u.id, userUpdate)),
203 toArray(),
204 catchError(err => this.restExtractor.handleError(err))
205 )
206 }
207
218b0874
C
208 getUserWithCache (userId: number) {
209 if (!this.userCache[userId]) {
9df52d66 210 this.userCache[userId] = this.getUser(userId).pipe(shareReplay())
218b0874
C
211 }
212
213 return this.userCache[userId]
214 }
215
76314386
RK
216 getUser (userId: number, withStats = false) {
217 const params = new HttpParams().append('withStats', withStats + '')
218 return this.authHttp.get<UserServerModel>(UserService.BASE_USERS_URL + userId, { params })
e724fa93
C
219 .pipe(catchError(err => this.restExtractor.handleError(err)))
220 }
221
8491293b
RK
222 getUsers (parameters: {
223 pagination: RestPagination
224 sort: SortMeta
225 search?: string
226 }): Observable<ResultList<UserServerModel>> {
227 const { pagination, sort, search } = parameters
228
e724fa93
C
229 let params = new HttpParams()
230 params = this.restService.addRestGetParams(params, pagination, sort)
231
8491293b
RK
232 if (search) {
233 const filters = this.restService.parseQueryStringFilter(search, {
234 blocked: {
235 prefix: 'banned:',
1a7d0887 236 isBoolean: true
8491293b
RK
237 }
238 })
239
240 params = this.restService.addObjectParams(params, filters)
241 }
24b9417c 242
d3217560 243 return this.authHttp.get<ResultList<UserServerModel>>(UserService.BASE_USERS_URL, { params })
e724fa93
C
244 .pipe(
245 map(res => this.restExtractor.convertResultListDateToHuman(res)),
246 map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
247 catchError(err => this.restExtractor.handleError(err))
248 )
249 }
250
d3217560 251 removeUser (usersArg: UserServerModel | UserServerModel[]) {
791645e6
C
252 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
253
254 return from(users)
255 .pipe(
256 concatMap(u => this.authHttp.delete(UserService.BASE_USERS_URL + u.id)),
257 toArray(),
258 catchError(err => this.restExtractor.handleError(err))
259 )
e724fa93
C
260 }
261
d3217560 262 banUsers (usersArg: UserServerModel | UserServerModel[], reason?: string) {
e724fa93 263 const body = reason ? { reason } : {}
791645e6 264 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
e724fa93 265
791645e6
C
266 return from(users)
267 .pipe(
268 concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/block', body)),
269 toArray(),
270 catchError(err => this.restExtractor.handleError(err))
271 )
e724fa93
C
272 }
273
d3217560 274 unbanUsers (usersArg: UserServerModel | UserServerModel[]) {
791645e6
C
275 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
276
277 return from(users)
278 .pipe(
279 concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/unblock', {})),
280 toArray(),
281 catchError(err => this.restExtractor.handleError(err))
282 )
e724fa93
C
283 }
284
5c20a455
C
285 getAnonymousOrLoggedUser () {
286 if (!this.authService.isLoggedIn()) {
287 return of(this.getAnonymousUser())
288 }
289
290 return this.authService.userInformationLoaded
291 .pipe(
292 first(),
293 map(() => this.authService.getUser())
294 )
295 }
296
d3217560 297 private formatUser (user: UserServerModel) {
e724fa93
C
298 let videoQuota
299 if (user.videoQuota === -1) {
bc99dfe5 300 videoQuota = '∞'
e724fa93 301 } else {
b4c3c51d 302 videoQuota = getBytes(user.videoQuota, 0)
e724fa93
C
303 }
304
b4c3c51d 305 const videoQuotaUsed = getBytes(user.videoQuotaUsed, 0)
e724fa93 306
4f5d0459
RK
307 let videoQuotaDaily: string
308 let videoQuotaUsedDaily: string
bc99dfe5
RK
309 if (user.videoQuotaDaily === -1) {
310 videoQuotaDaily = '∞'
b4c3c51d 311 videoQuotaUsedDaily = getBytes(0, 0) + ''
bc99dfe5 312 } else {
b4c3c51d
C
313 videoQuotaDaily = getBytes(user.videoQuotaDaily, 0) + ''
314 videoQuotaUsedDaily = getBytes(user.videoQuotaUsedDaily || 0, 0) + ''
bc99dfe5
RK
315 }
316
e724fa93 317 const roleLabels: { [ id in UserRole ]: string } = {
66357162
C
318 [UserRole.USER]: $localize`User`,
319 [UserRole.ADMINISTRATOR]: $localize`Administrator`,
320 [UserRole.MODERATOR]: $localize`Moderator`
e724fa93
C
321 }
322
323 return Object.assign(user, {
324 roleLabel: roleLabels[user.role],
325 videoQuota,
bc99dfe5
RK
326 videoQuotaUsed,
327 rawVideoQuota: user.videoQuota,
328 rawVideoQuotaUsed: user.videoQuotaUsed,
329 videoQuotaDaily,
330 videoQuotaUsedDaily,
331 rawVideoQuotaDaily: user.videoQuotaDaily,
332 rawVideoQuotaUsedDaily: user.videoQuotaUsedDaily
e724fa93
C
333 })
334 }
629d8d6f 335}