aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/shared')
-rw-r--r--client/src/app/shared/shared-moderation/shared-moderation.module.ts8
-rw-r--r--client/src/app/shared/shared-moderation/user-ban-modal.component.ts7
-rw-r--r--client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts11
-rw-r--r--client/src/app/shared/shared-users/index.ts4
-rw-r--r--client/src/app/shared/shared-users/shared-users.module.ts21
-rw-r--r--client/src/app/shared/shared-users/user-admin.service.ts139
-rw-r--r--client/src/app/shared/shared-users/user-signup.service.ts56
7 files changed, 235 insertions, 11 deletions
diff --git a/client/src/app/shared/shared-moderation/shared-moderation.module.ts b/client/src/app/shared/shared-moderation/shared-moderation.module.ts
index 7cadda67c..dac4ae951 100644
--- a/client/src/app/shared/shared-moderation/shared-moderation.module.ts
+++ b/client/src/app/shared/shared-moderation/shared-moderation.module.ts
@@ -1,10 +1,13 @@
1 1
2import { NgModule } from '@angular/core' 2import { NgModule } from '@angular/core'
3import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module'
3import { SharedFormModule } from '../shared-forms/shared-form.module' 4import { SharedFormModule } from '../shared-forms/shared-form.module'
4import { SharedGlobalIconModule } from '../shared-icons' 5import { SharedGlobalIconModule } from '../shared-icons'
5import { SharedMainModule } from '../shared-main/shared-main.module' 6import { SharedMainModule } from '../shared-main/shared-main.module'
7import { SharedUsersModule } from '../shared-users'
6import { SharedVideoCommentModule } from '../shared-video-comment' 8import { SharedVideoCommentModule } from '../shared-video-comment'
7import { AbuseService } from './abuse.service' 9import { AbuseService } from './abuse.service'
10import { AccountBlockBadgesComponent } from './account-block-badges.component'
8import { BatchDomainsModalComponent } from './batch-domains-modal.component' 11import { BatchDomainsModalComponent } from './batch-domains-modal.component'
9import { BlocklistService } from './blocklist.service' 12import { BlocklistService } from './blocklist.service'
10import { BulkService } from './bulk.service' 13import { BulkService } from './bulk.service'
@@ -13,8 +16,6 @@ import { UserBanModalComponent } from './user-ban-modal.component'
13import { UserModerationDropdownComponent } from './user-moderation-dropdown.component' 16import { UserModerationDropdownComponent } from './user-moderation-dropdown.component'
14import { VideoBlockComponent } from './video-block.component' 17import { VideoBlockComponent } from './video-block.component'
15import { VideoBlockService } from './video-block.service' 18import { VideoBlockService } from './video-block.service'
16import { AccountBlockBadgesComponent } from './account-block-badges.component'
17import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module'
18 19
19@NgModule({ 20@NgModule({
20 imports: [ 21 imports: [
@@ -22,7 +23,8 @@ import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image
22 SharedFormModule, 23 SharedFormModule,
23 SharedGlobalIconModule, 24 SharedGlobalIconModule,
24 SharedVideoCommentModule, 25 SharedVideoCommentModule,
25 SharedActorImageModule 26 SharedActorImageModule,
27 SharedUsersModule
26 ], 28 ],
27 29
28 declarations: [ 30 declarations: [
diff --git a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
index b2ce019c5..17cad18ec 100644
--- a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
+++ b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
@@ -1,10 +1,11 @@
1import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' 1import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
2import { Notifier, UserService } from '@app/core' 2import { Notifier } from '@app/core'
3import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' 3import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
4import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 4import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
5import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' 5import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
6import { User } from '@shared/models' 6import { User } from '@shared/models'
7import { USER_BAN_REASON_VALIDATOR } from '../form-validators/user-validators' 7import { USER_BAN_REASON_VALIDATOR } from '../form-validators/user-validators'
8import { UserAdminService } from '../shared-users'
8 9
9@Component({ 10@Component({
10 selector: 'my-user-ban-modal', 11 selector: 'my-user-ban-modal',
@@ -23,7 +24,7 @@ export class UserBanModalComponent extends FormReactive implements OnInit {
23 protected formValidatorService: FormValidatorService, 24 protected formValidatorService: FormValidatorService,
24 private modalService: NgbModal, 25 private modalService: NgbModal,
25 private notifier: Notifier, 26 private notifier: Notifier,
26 private userService: UserService 27 private userAdminService: UserAdminService
27 ) { 28 ) {
28 super() 29 super()
29 } 30 }
@@ -50,7 +51,7 @@ export class UserBanModalComponent extends FormReactive implements OnInit {
50 banUser () { 51 banUser () {
51 const reason = this.form.value['reason'] || undefined 52 const reason = this.form.value['reason'] || undefined
52 53
53 this.userService.banUsers(this.usersToBan, reason) 54 this.userAdminService.banUsers(this.usersToBan, reason)
54 .subscribe({ 55 .subscribe({
55 next: () => { 56 next: () => {
56 const message = Array.isArray(this.usersToBan) 57 const message = Array.isArray(this.usersToBan)
diff --git a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
index e2cd2cdc1..0d19565ef 100644
--- a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
+++ b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
@@ -1,7 +1,8 @@
1import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core' 1import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core'
2import { AuthService, ConfirmService, Notifier, ServerService, UserService } from '@app/core' 2import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core'
3import { Account, DropdownAction } from '@app/shared/shared-main' 3import { Account, DropdownAction } from '@app/shared/shared-main'
4import { BulkRemoveCommentsOfBody, User, UserRight } from '@shared/models' 4import { BulkRemoveCommentsOfBody, User, UserRight } from '@shared/models'
5import { UserAdminService } from '../shared-users'
5import { BlocklistService } from './blocklist.service' 6import { BlocklistService } from './blocklist.service'
6import { BulkService } from './bulk.service' 7import { BulkService } from './bulk.service'
7import { UserBanModalComponent } from './user-ban-modal.component' 8import { UserBanModalComponent } from './user-ban-modal.component'
@@ -35,7 +36,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
35 private notifier: Notifier, 36 private notifier: Notifier,
36 private confirmService: ConfirmService, 37 private confirmService: ConfirmService,
37 private serverService: ServerService, 38 private serverService: ServerService,
38 private userService: UserService, 39 private userAdminService: UserAdminService,
39 private blocklistService: BlocklistService, 40 private blocklistService: BlocklistService,
40 private bulkService: BulkService 41 private bulkService: BulkService
41 ) { } 42 ) { }
@@ -66,7 +67,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
66 const res = await this.confirmService.confirm($localize`Do you really want to unban ${user.username}?`, $localize`Unban`) 67 const res = await this.confirmService.confirm($localize`Do you really want to unban ${user.username}?`, $localize`Unban`)
67 if (res === false) return 68 if (res === false) return
68 69
69 this.userService.unbanUsers(user) 70 this.userAdminService.unbanUsers(user)
70 .subscribe({ 71 .subscribe({
71 next: () => { 72 next: () => {
72 this.notifier.success($localize`User ${user.username} unbanned.`) 73 this.notifier.success($localize`User ${user.username} unbanned.`)
@@ -87,7 +88,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
87 const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`) 88 const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`)
88 if (res === false) return 89 if (res === false) return
89 90
90 this.userService.removeUser(user) 91 this.userAdminService.removeUser(user)
91 .subscribe({ 92 .subscribe({
92 next: () => { 93 next: () => {
93 this.notifier.success($localize`User ${user.username} deleted.`) 94 this.notifier.success($localize`User ${user.username} deleted.`)
@@ -99,7 +100,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
99 } 100 }
100 101
101 setEmailAsVerified (user: User) { 102 setEmailAsVerified (user: User) {
102 this.userService.updateUser(user.id, { emailVerified: true }) 103 this.userAdminService.updateUser(user.id, { emailVerified: true })
103 .subscribe({ 104 .subscribe({
104 next: () => { 105 next: () => {
105 this.notifier.success($localize`User ${user.username} email set as verified`) 106 this.notifier.success($localize`User ${user.username} email set as verified`)
diff --git a/client/src/app/shared/shared-users/index.ts b/client/src/app/shared/shared-users/index.ts
new file mode 100644
index 000000000..8f90f2515
--- /dev/null
+++ b/client/src/app/shared/shared-users/index.ts
@@ -0,0 +1,4 @@
1export * from './user-admin.service'
2export * from './user-signup.service'
3
4export * from './shared-users.module'
diff --git a/client/src/app/shared/shared-users/shared-users.module.ts b/client/src/app/shared/shared-users/shared-users.module.ts
new file mode 100644
index 000000000..2a1dadf20
--- /dev/null
+++ b/client/src/app/shared/shared-users/shared-users.module.ts
@@ -0,0 +1,21 @@
1
2import { NgModule } from '@angular/core'
3import { SharedMainModule } from '../shared-main/shared-main.module'
4import { UserAdminService } from './user-admin.service'
5import { UserSignupService } from './user-signup.service'
6
7@NgModule({
8 imports: [
9 SharedMainModule
10 ],
11
12 declarations: [ ],
13
14 exports: [],
15
16 providers: [
17 UserSignupService,
18 UserAdminService
19 ]
20})
21export class SharedUsersModule { }
diff --git a/client/src/app/shared/shared-users/user-admin.service.ts b/client/src/app/shared/shared-users/user-admin.service.ts
new file mode 100644
index 000000000..3db271c4a
--- /dev/null
+++ b/client/src/app/shared/shared-users/user-admin.service.ts
@@ -0,0 +1,139 @@
1import { SortMeta } from 'primeng/api'
2import { from, Observable } from 'rxjs'
3import { catchError, concatMap, map, toArray } from 'rxjs/operators'
4import { HttpClient, HttpParams } from '@angular/common/http'
5import { Injectable } from '@angular/core'
6import { RestExtractor, RestPagination, RestService, UserService } from '@app/core'
7import { getBytes } from '@root-helpers/bytes'
8import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate } from '@shared/models'
9
10@Injectable()
11export class UserAdminService {
12
13 constructor (
14 private authHttp: HttpClient,
15 private restExtractor: RestExtractor,
16 private restService: RestService
17 ) { }
18
19 addUser (userCreate: UserCreate) {
20 return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
21 .pipe(catchError(err => this.restExtractor.handleError(err)))
22 }
23
24 updateUser (userId: number, userUpdate: UserUpdate) {
25 return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
26 .pipe(catchError(err => this.restExtractor.handleError(err)))
27 }
28
29 updateUsers (users: UserServerModel[], userUpdate: UserUpdate) {
30 return from(users)
31 .pipe(
32 concatMap(u => this.authHttp.put(UserService.BASE_USERS_URL + u.id, userUpdate)),
33 toArray(),
34 catchError(err => this.restExtractor.handleError(err))
35 )
36 }
37
38 getUsers (parameters: {
39 pagination: RestPagination
40 sort: SortMeta
41 search?: string
42 }): Observable<ResultList<UserServerModel>> {
43 const { pagination, sort, search } = parameters
44
45 let params = new HttpParams()
46 params = this.restService.addRestGetParams(params, pagination, sort)
47
48 if (search) {
49 const filters = this.restService.parseQueryStringFilter(search, {
50 blocked: {
51 prefix: 'banned:',
52 isBoolean: true
53 }
54 })
55
56 params = this.restService.addObjectParams(params, filters)
57 }
58
59 return this.authHttp.get<ResultList<UserServerModel>>(UserService.BASE_USERS_URL, { params })
60 .pipe(
61 map(res => this.restExtractor.convertResultListDateToHuman(res)),
62 map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
63 catchError(err => this.restExtractor.handleError(err))
64 )
65 }
66
67 removeUser (usersArg: UserServerModel | UserServerModel[]) {
68 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
69
70 return from(users)
71 .pipe(
72 concatMap(u => this.authHttp.delete(UserService.BASE_USERS_URL + u.id)),
73 toArray(),
74 catchError(err => this.restExtractor.handleError(err))
75 )
76 }
77
78 banUsers (usersArg: UserServerModel | UserServerModel[], reason?: string) {
79 const body = reason ? { reason } : {}
80 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
81
82 return from(users)
83 .pipe(
84 concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/block', body)),
85 toArray(),
86 catchError(err => this.restExtractor.handleError(err))
87 )
88 }
89
90 unbanUsers (usersArg: UserServerModel | UserServerModel[]) {
91 const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
92
93 return from(users)
94 .pipe(
95 concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/unblock', {})),
96 toArray(),
97 catchError(err => this.restExtractor.handleError(err))
98 )
99 }
100
101 private formatUser (user: UserServerModel) {
102 let videoQuota
103 if (user.videoQuota === -1) {
104 videoQuota = '∞'
105 } else {
106 videoQuota = getBytes(user.videoQuota, 0)
107 }
108
109 const videoQuotaUsed = getBytes(user.videoQuotaUsed, 0)
110
111 let videoQuotaDaily: string
112 let videoQuotaUsedDaily: string
113 if (user.videoQuotaDaily === -1) {
114 videoQuotaDaily = '∞'
115 videoQuotaUsedDaily = getBytes(0, 0) + ''
116 } else {
117 videoQuotaDaily = getBytes(user.videoQuotaDaily, 0) + ''
118 videoQuotaUsedDaily = getBytes(user.videoQuotaUsedDaily || 0, 0) + ''
119 }
120
121 const roleLabels: { [ id in UserRole ]: string } = {
122 [UserRole.USER]: $localize`User`,
123 [UserRole.ADMINISTRATOR]: $localize`Administrator`,
124 [UserRole.MODERATOR]: $localize`Moderator`
125 }
126
127 return Object.assign(user, {
128 roleLabel: roleLabels[user.role],
129 videoQuota,
130 videoQuotaUsed,
131 rawVideoQuota: user.videoQuota,
132 rawVideoQuotaUsed: user.videoQuotaUsed,
133 videoQuotaDaily,
134 videoQuotaUsedDaily,
135 rawVideoQuotaDaily: user.videoQuotaDaily,
136 rawVideoQuotaUsedDaily: user.videoQuotaUsedDaily
137 })
138 }
139}
diff --git a/client/src/app/shared/shared-users/user-signup.service.ts b/client/src/app/shared/shared-users/user-signup.service.ts
new file mode 100644
index 000000000..46fe34af1
--- /dev/null
+++ b/client/src/app/shared/shared-users/user-signup.service.ts
@@ -0,0 +1,56 @@
1import { catchError, tap } from 'rxjs/operators'
2import { HttpClient } from '@angular/common/http'
3import { Injectable } from '@angular/core'
4import { RestExtractor, UserService } from '@app/core'
5import { UserRegister } from '@shared/models'
6
7@Injectable()
8export class UserSignupService {
9 constructor (
10 private authHttp: HttpClient,
11 private restExtractor: RestExtractor,
12 private userService: UserService
13 ) { }
14
15 signup (userCreate: UserRegister) {
16 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
17 .pipe(
18 tap(() => this.userService.setSignupInThisSession(true)),
19 catchError(err => this.restExtractor.handleError(err))
20 )
21 }
22
23 verifyEmail (userId: number, verificationString: string, isPendingEmail: boolean) {
24 const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email`
25 const body = {
26 verificationString,
27 isPendingEmail
28 }
29
30 return this.authHttp.post(url, body)
31 .pipe(catchError(res => this.restExtractor.handleError(res)))
32 }
33
34 askSendVerifyEmail (email: string) {
35 const url = UserService.BASE_USERS_URL + '/ask-send-verify-email'
36
37 return this.authHttp.post(url, { email })
38 .pipe(catchError(err => this.restExtractor.handleError(err)))
39 }
40
41 getNewUsername (oldDisplayName: string, newDisplayName: string, currentUsername: string) {
42 // Don't update display name, the user seems to have changed it
43 if (this.displayNameToUsername(oldDisplayName) !== currentUsername) return currentUsername
44
45 return this.displayNameToUsername(newDisplayName)
46 }
47
48 private displayNameToUsername (displayName: string) {
49 if (!displayName) return ''
50
51 return displayName
52 .toLowerCase()
53 .replace(/\s/g, '_')
54 .replace(/[^a-z0-9_.]/g, '')
55 }
56}