aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+admin
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-10-05 15:24:29 +0200
committerChocobozzz <me@florianbigard.com>2018-10-05 17:02:09 +0200
commite724fa93c71d76d709e819a05e5e2904a3c4205b (patch)
treec9bd410253f4ceac8e330541580445ca313583ac /client/src/app/+admin
parent21c54ac5f684f8b72bcde45cd8327ee21f574f22 (diff)
downloadPeerTube-e724fa93c71d76d709e819a05e5e2904a3c4205b.tar.gz
PeerTube-e724fa93c71d76d709e819a05e5e2904a3c4205b.tar.zst
PeerTube-e724fa93c71d76d709e819a05e5e2904a3c4205b.zip
Move user moderation tool in a separate component
Diffstat (limited to 'client/src/app/+admin')
-rw-r--r--client/src/app/+admin/admin.module.ts5
-rw-r--r--client/src/app/+admin/users/index.ts1
-rw-r--r--client/src/app/+admin/users/shared/index.ts1
-rw-r--r--client/src/app/+admin/users/shared/user.service.ts96
-rw-r--r--client/src/app/+admin/users/user-edit/user-create.component.ts2
-rw-r--r--client/src/app/+admin/users/user-edit/user-update.component.ts2
-rw-r--r--client/src/app/+admin/users/user-list/user-ban-modal.component.html32
-rw-r--r--client/src/app/+admin/users/user-list/user-ban-modal.component.scss6
-rw-r--r--client/src/app/+admin/users/user-list/user-ban-modal.component.ts69
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.html3
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.ts95
11 files changed, 7 insertions, 305 deletions
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts
index 5784609ef..8c6db98d9 100644
--- a/client/src/app/+admin/admin.module.ts
+++ b/client/src/app/+admin/admin.module.ts
@@ -10,9 +10,8 @@ import { FollowingListComponent } from './follows/following-list/following-list.
10import { JobsComponent } from './jobs/job.component' 10import { JobsComponent } from './jobs/job.component'
11import { JobsListComponent } from './jobs/jobs-list/jobs-list.component' 11import { JobsListComponent } from './jobs/jobs-list/jobs-list.component'
12import { JobService } from './jobs/shared/job.service' 12import { JobService } from './jobs/shared/job.service'
13import { UserCreateComponent, UserListComponent, UsersComponent, UserService, UserUpdateComponent } from './users' 13import { UserCreateComponent, UserListComponent, UsersComponent, UserUpdateComponent } from './users'
14import { ModerationCommentModalComponent, VideoAbuseListComponent, VideoBlacklistListComponent } from './moderation' 14import { ModerationCommentModalComponent, VideoAbuseListComponent, VideoBlacklistListComponent } from './moderation'
15import { UserBanModalComponent } from '@app/+admin/users/user-list/user-ban-modal.component'
16import { ModerationComponent } from '@app/+admin/moderation/moderation.component' 15import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
17import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component' 16import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
18import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service' 17import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service'
@@ -37,7 +36,6 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
37 UserCreateComponent, 36 UserCreateComponent,
38 UserUpdateComponent, 37 UserUpdateComponent,
39 UserListComponent, 38 UserListComponent,
40 UserBanModalComponent,
41 39
42 ModerationComponent, 40 ModerationComponent,
43 VideoBlacklistListComponent, 41 VideoBlacklistListComponent,
@@ -58,7 +56,6 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
58 providers: [ 56 providers: [
59 FollowService, 57 FollowService,
60 RedundancyService, 58 RedundancyService,
61 UserService,
62 JobService, 59 JobService,
63 ConfigService 60 ConfigService
64 ] 61 ]
diff --git a/client/src/app/+admin/users/index.ts b/client/src/app/+admin/users/index.ts
index efcd0d9cb..156e54d89 100644
--- a/client/src/app/+admin/users/index.ts
+++ b/client/src/app/+admin/users/index.ts
@@ -1,4 +1,3 @@
1export * from './shared'
2export * from './user-edit' 1export * from './user-edit'
3export * from './user-list' 2export * from './user-list'
4export * from './users.component' 3export * from './users.component'
diff --git a/client/src/app/+admin/users/shared/index.ts b/client/src/app/+admin/users/shared/index.ts
deleted file mode 100644
index 1f1302dc5..000000000
--- a/client/src/app/+admin/users/shared/index.ts
+++ /dev/null
@@ -1 +0,0 @@
1export * from './user.service'
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts
deleted file mode 100644
index 470beef08..000000000
--- a/client/src/app/+admin/users/shared/user.service.ts
+++ /dev/null
@@ -1,96 +0,0 @@
1import { catchError, map } from 'rxjs/operators'
2import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core'
4import { BytesPipe } from 'ngx-pipes'
5import { SortMeta } from 'primeng/components/common/sortmeta'
6import { Observable } from 'rxjs'
7import { ResultList, UserCreate, UserUpdate, User, UserRole } from '../../../../../../shared'
8import { environment } from '../../../../environments/environment'
9import { RestExtractor, RestPagination, RestService } from '../../../shared'
10import { I18n } from '@ngx-translate/i18n-polyfill'
11
12@Injectable()
13export class UserService {
14 private static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/'
15 private bytesPipe = new BytesPipe()
16
17 constructor (
18 private authHttp: HttpClient,
19 private restService: RestService,
20 private restExtractor: RestExtractor,
21 private i18n: I18n
22 ) { }
23
24 addUser (userCreate: UserCreate) {
25 return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
26 .pipe(
27 map(this.restExtractor.extractDataBool),
28 catchError(err => this.restExtractor.handleError(err))
29 )
30 }
31
32 updateUser (userId: number, userUpdate: UserUpdate) {
33 return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
34 .pipe(
35 map(this.restExtractor.extractDataBool),
36 catchError(err => this.restExtractor.handleError(err))
37 )
38 }
39
40 getUser (userId: number) {
41 return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId)
42 .pipe(catchError(err => this.restExtractor.handleError(err)))
43 }
44
45 getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> {
46 let params = new HttpParams()
47 params = this.restService.addRestGetParams(params, pagination, sort)
48
49 return this.authHttp.get<ResultList<User>>(UserService.BASE_USERS_URL, { params })
50 .pipe(
51 map(res => this.restExtractor.convertResultListDateToHuman(res)),
52 map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
53 catchError(err => this.restExtractor.handleError(err))
54 )
55 }
56
57 removeUser (user: User) {
58 return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
59 .pipe(catchError(err => this.restExtractor.handleError(err)))
60 }
61
62 banUser (user: User, reason?: string) {
63 const body = reason ? { reason } : {}
64
65 return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/block', body)
66 .pipe(catchError(err => this.restExtractor.handleError(err)))
67 }
68
69 unbanUser (user: User) {
70 return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/unblock', {})
71 .pipe(catchError(err => this.restExtractor.handleError(err)))
72 }
73
74 private formatUser (user: User) {
75 let videoQuota
76 if (user.videoQuota === -1) {
77 videoQuota = this.i18n('Unlimited')
78 } else {
79 videoQuota = this.bytesPipe.transform(user.videoQuota, 0)
80 }
81
82 const videoQuotaUsed = this.bytesPipe.transform(user.videoQuotaUsed, 0)
83
84 const roleLabels: { [ id in UserRole ]: string } = {
85 [UserRole.USER]: this.i18n('User'),
86 [UserRole.ADMINISTRATOR]: this.i18n('Administrator'),
87 [UserRole.MODERATOR]: this.i18n('Moderator')
88 }
89
90 return Object.assign(user, {
91 roleLabel: roleLabels[user.role],
92 videoQuota,
93 videoQuotaUsed
94 })
95 }
96}
diff --git a/client/src/app/+admin/users/user-edit/user-create.component.ts b/client/src/app/+admin/users/user-edit/user-create.component.ts
index 132e280b9..dd8e4efd5 100644
--- a/client/src/app/+admin/users/user-edit/user-create.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-create.component.ts
@@ -1,7 +1,6 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { UserService } from '../shared'
5import { ServerService } from '../../../core' 4import { ServerService } from '../../../core'
6import { UserCreate, UserRole } from '../../../../../../shared' 5import { UserCreate, UserRole } from '../../../../../../shared'
7import { UserEdit } from './user-edit' 6import { UserEdit } from './user-edit'
@@ -9,6 +8,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
9import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 8import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
10import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' 9import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
11import { ConfigService } from '@app/+admin/config/shared/config.service' 10import { ConfigService } from '@app/+admin/config/shared/config.service'
11import { UserService } from '@app/shared'
12 12
13@Component({ 13@Component({
14 selector: 'my-user-create', 14 selector: 'my-user-create',
diff --git a/client/src/app/+admin/users/user-edit/user-update.component.ts b/client/src/app/+admin/users/user-edit/user-update.component.ts
index 9eb91ac95..cd3885a99 100644
--- a/client/src/app/+admin/users/user-edit/user-update.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-update.component.ts
@@ -2,7 +2,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { Subscription } from 'rxjs' 3import { Subscription } from 'rxjs'
4import { NotificationsService } from 'angular2-notifications' 4import { NotificationsService } from 'angular2-notifications'
5import { UserService } from '../shared'
6import { ServerService } from '../../../core' 5import { ServerService } from '../../../core'
7import { UserEdit } from './user-edit' 6import { UserEdit } from './user-edit'
8import { User, UserUpdate } from '../../../../../../shared' 7import { User, UserUpdate } from '../../../../../../shared'
@@ -10,6 +9,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
10import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 9import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
11import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' 10import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
12import { ConfigService } from '@app/+admin/config/shared/config.service' 11import { ConfigService } from '@app/+admin/config/shared/config.service'
12import { UserService } from '@app/shared'
13 13
14@Component({ 14@Component({
15 selector: 'my-user-update', 15 selector: 'my-user-update',
diff --git a/client/src/app/+admin/users/user-list/user-ban-modal.component.html b/client/src/app/+admin/users/user-list/user-ban-modal.component.html
deleted file mode 100644
index b2958caa4..000000000
--- a/client/src/app/+admin/users/user-list/user-ban-modal.component.html
+++ /dev/null
@@ -1,32 +0,0 @@
1<ng-template #modal>
2 <div class="modal-header">
3 <h4 i18n class="modal-title">Ban {{ userToBan.username }}</h4>
4 <span class="close" aria-hidden="true" (click)="hideBanUserModal()"></span>
5 </div>
6
7 <div class="modal-body">
8 <form novalidate [formGroup]="form" (ngSubmit)="banUser()">
9 <div class="form-group">
10 <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
11 </textarea>
12 <div *ngIf="formErrors.reason" class="form-error">
13 {{ formErrors.reason }}
14 </div>
15 </div>
16
17 <div i18n>
18 A banned user will no longer be able to login.
19 </div>
20
21 <div class="form-group inputs">
22 <span i18n class="action-button action-button-cancel" (click)="hideBanUserModal()">Cancel</span>
23
24 <input
25 type="submit" i18n-value value="Ban this user" class="action-button-submit"
26 [disabled]="!form.valid"
27 >
28 </div>
29 </form>
30 </div>
31
32</ng-template> \ No newline at end of file
diff --git a/client/src/app/+admin/users/user-list/user-ban-modal.component.scss b/client/src/app/+admin/users/user-list/user-ban-modal.component.scss
deleted file mode 100644
index 84562f15c..000000000
--- a/client/src/app/+admin/users/user-list/user-ban-modal.component.scss
+++ /dev/null
@@ -1,6 +0,0 @@
1@import 'variables';
2@import 'mixins';
3
4textarea {
5 @include peertube-textarea(100%, 60px);
6}
diff --git a/client/src/app/+admin/users/user-list/user-ban-modal.component.ts b/client/src/app/+admin/users/user-list/user-ban-modal.component.ts
deleted file mode 100644
index 4fd4d561c..000000000
--- a/client/src/app/+admin/users/user-list/user-ban-modal.component.ts
+++ /dev/null
@@ -1,69 +0,0 @@
1import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
2import { NotificationsService } from 'angular2-notifications'
3import { FormReactive, UserValidatorsService } from '../../../shared'
4import { UserService } from '../shared'
5import { I18n } from '@ngx-translate/i18n-polyfill'
6import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
7import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
8import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
9import { User } from '../../../../../../shared'
10
11@Component({
12 selector: 'my-user-ban-modal',
13 templateUrl: './user-ban-modal.component.html',
14 styleUrls: [ './user-ban-modal.component.scss' ]
15})
16export class UserBanModalComponent extends FormReactive implements OnInit {
17 @ViewChild('modal') modal: NgbModal
18 @Output() userBanned = new EventEmitter<User>()
19
20 private userToBan: User
21 private openedModal: NgbModalRef
22
23 constructor (
24 protected formValidatorService: FormValidatorService,
25 private modalService: NgbModal,
26 private notificationsService: NotificationsService,
27 private userService: UserService,
28 private userValidatorsService: UserValidatorsService,
29 private i18n: I18n
30 ) {
31 super()
32 }
33
34 ngOnInit () {
35 this.buildForm({
36 reason: this.userValidatorsService.USER_BAN_REASON
37 })
38 }
39
40 openModal (user: User) {
41 this.userToBan = user
42 this.openedModal = this.modalService.open(this.modal)
43 }
44
45 hideBanUserModal () {
46 this.userToBan = undefined
47 this.openedModal.close()
48 }
49
50 async banUser () {
51 const reason = this.form.value['reason'] || undefined
52
53 this.userService.banUser(this.userToBan, reason)
54 .subscribe(
55 () => {
56 this.notificationsService.success(
57 this.i18n('Success'),
58 this.i18n('User {{username}} banned.', { username: this.userToBan.username })
59 )
60
61 this.userBanned.emit(this.userToBan)
62 this.hideBanUserModal()
63 },
64
65 err => this.notificationsService.error(this.i18n('Error'), err.message)
66 )
67 }
68
69}
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html
index bb1b26442..2479ce9e4 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.html
+++ b/client/src/app/+admin/users/user-list/user-list.component.html
@@ -40,7 +40,7 @@
40 <td>{{ user.roleLabel }}</td> 40 <td>{{ user.roleLabel }}</td>
41 <td>{{ user.createdAt }}</td> 41 <td>{{ user.createdAt }}</td>
42 <td class="action-cell"> 42 <td class="action-cell">
43 <my-action-dropdown i18n-label label="Actions" [actions]="userActions" [entry]="user"></my-action-dropdown> 43 <my-user-moderation-dropdown [user]="user" (userChanged)="onUserChanged()"></my-user-moderation-dropdown>
44 </td> 44 </td>
45 </tr> 45 </tr>
46 </ng-template> 46 </ng-template>
@@ -55,4 +55,3 @@
55 </ng-template> 55 </ng-template>
56</p-table> 56</p-table>
57 57
58<my-user-ban-modal #userBanModal (userBanned)="onUserBanned()"></my-user-ban-modal> \ No newline at end of file
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts
index 100ffc00e..dee3ed643 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.ts
+++ b/client/src/app/+admin/users/user-list/user-list.component.ts
@@ -1,13 +1,9 @@
1import { Component, OnInit, ViewChild } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { NotificationsService } from 'angular2-notifications' 2import { NotificationsService } from 'angular2-notifications'
3import { SortMeta } from 'primeng/components/common/sortmeta' 3import { SortMeta } from 'primeng/components/common/sortmeta'
4import { ConfirmService } from '../../../core' 4import { ConfirmService } from '../../../core'
5import { RestPagination, RestTable } from '../../../shared' 5import { RestPagination, RestTable, UserService } from '../../../shared'
6import { UserService } from '../shared'
7import { I18n } from '@ngx-translate/i18n-polyfill' 6import { I18n } from '@ngx-translate/i18n-polyfill'
8import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
9import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
10import { UserBanModalComponent } from '@app/+admin/users/user-list/user-ban-modal.component'
11import { User } from '../../../../../../shared' 7import { User } from '../../../../../../shared'
12 8
13@Component({ 9@Component({
@@ -16,16 +12,11 @@ import { User } from '../../../../../../shared'
16 styleUrls: [ './user-list.component.scss' ] 12 styleUrls: [ './user-list.component.scss' ]
17}) 13})
18export class UserListComponent extends RestTable implements OnInit { 14export class UserListComponent extends RestTable implements OnInit {
19 @ViewChild('userBanModal') userBanModal: UserBanModalComponent
20
21 users: User[] = [] 15 users: User[] = []
22 totalRecords = 0 16 totalRecords = 0
23 rowsPerPage = 10 17 rowsPerPage = 10
24 sort: SortMeta = { field: 'createdAt', order: 1 } 18 sort: SortMeta = { field: 'createdAt', order: 1 }
25 pagination: RestPagination = { count: this.rowsPerPage, start: 0 } 19 pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
26 userActions: DropdownAction<User>[] = []
27
28 private openedModal: NgbModalRef
29 20
30 constructor ( 21 constructor (
31 private notificationsService: NotificationsService, 22 private notificationsService: NotificationsService,
@@ -34,96 +25,16 @@ export class UserListComponent extends RestTable implements OnInit {
34 private i18n: I18n 25 private i18n: I18n
35 ) { 26 ) {
36 super() 27 super()
37
38 this.userActions = [
39 {
40 label: this.i18n('Edit'),
41 linkBuilder: this.getRouterUserEditLink
42 },
43 {
44 label: this.i18n('Delete'),
45 handler: user => this.removeUser(user)
46 },
47 {
48 label: this.i18n('Ban'),
49 handler: user => this.openBanUserModal(user),
50 isDisplayed: user => !user.blocked
51 },
52 {
53 label: this.i18n('Unban'),
54 handler: user => this.unbanUser(user),
55 isDisplayed: user => user.blocked
56 }
57 ]
58 } 28 }
59 29
60 ngOnInit () { 30 ngOnInit () {
61 this.loadSort() 31 this.loadSort()
62 } 32 }
63 33
64 hideBanUserModal () { 34 onUserChanged () {
65 this.openedModal.close()
66 }
67
68 openBanUserModal (user: User) {
69 if (user.username === 'root') {
70 this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
71 return
72 }
73
74 this.userBanModal.openModal(user)
75 }
76
77 onUserBanned () {
78 this.loadData() 35 this.loadData()
79 } 36 }
80 37
81 async unbanUser (user: User) {
82 const message = this.i18n('Do you really want to unban {{username}}?', { username: user.username })
83 const res = await this.confirmService.confirm(message, this.i18n('Unban'))
84 if (res === false) return
85
86 this.userService.unbanUser(user)
87 .subscribe(
88 () => {
89 this.notificationsService.success(
90 this.i18n('Success'),
91 this.i18n('User {{username}} unbanned.', { username: user.username })
92 )
93 this.loadData()
94 },
95
96 err => this.notificationsService.error(this.i18n('Error'), err.message)
97 )
98 }
99
100 async removeUser (user: User) {
101 if (user.username === 'root') {
102 this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot delete root.'))
103 return
104 }
105
106 const message = this.i18n('If you remove this user, you will not be able to create another with the same username!')
107 const res = await this.confirmService.confirm(message, this.i18n('Delete'))
108 if (res === false) return
109
110 this.userService.removeUser(user).subscribe(
111 () => {
112 this.notificationsService.success(
113 this.i18n('Success'),
114 this.i18n('User {{username}} deleted.', { username: user.username })
115 )
116 this.loadData()
117 },
118
119 err => this.notificationsService.error(this.i18n('Error'), err.message)
120 )
121 }
122
123 getRouterUserEditLink (user: User) {
124 return [ '/admin', 'users', 'update', user.id ]
125 }
126
127 protected loadData () { 38 protected loadData () {
128 this.userService.getUsers(this.pagination, this.sort) 39 this.userService.getUsers(this.pagination, this.sort)
129 .subscribe( 40 .subscribe(