Move user moderation tool in a separate component
This commit is contained in:
parent
21c54ac5f6
commit
e724fa93c7
|
@ -10,9 +10,8 @@ import { FollowingListComponent } from './follows/following-list/following-list.
|
||||||
import { JobsComponent } from './jobs/job.component'
|
import { JobsComponent } from './jobs/job.component'
|
||||||
import { JobsListComponent } from './jobs/jobs-list/jobs-list.component'
|
import { JobsListComponent } from './jobs/jobs-list/jobs-list.component'
|
||||||
import { JobService } from './jobs/shared/job.service'
|
import { JobService } from './jobs/shared/job.service'
|
||||||
import { UserCreateComponent, UserListComponent, UsersComponent, UserService, UserUpdateComponent } from './users'
|
import { UserCreateComponent, UserListComponent, UsersComponent, UserUpdateComponent } from './users'
|
||||||
import { ModerationCommentModalComponent, VideoAbuseListComponent, VideoBlacklistListComponent } from './moderation'
|
import { ModerationCommentModalComponent, VideoAbuseListComponent, VideoBlacklistListComponent } from './moderation'
|
||||||
import { UserBanModalComponent } from '@app/+admin/users/user-list/user-ban-modal.component'
|
|
||||||
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
||||||
import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
|
import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
|
||||||
import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service'
|
import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service'
|
||||||
|
@ -37,7 +36,6 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
|
||||||
UserCreateComponent,
|
UserCreateComponent,
|
||||||
UserUpdateComponent,
|
UserUpdateComponent,
|
||||||
UserListComponent,
|
UserListComponent,
|
||||||
UserBanModalComponent,
|
|
||||||
|
|
||||||
ModerationComponent,
|
ModerationComponent,
|
||||||
VideoBlacklistListComponent,
|
VideoBlacklistListComponent,
|
||||||
|
@ -58,7 +56,6 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
|
||||||
providers: [
|
providers: [
|
||||||
FollowService,
|
FollowService,
|
||||||
RedundancyService,
|
RedundancyService,
|
||||||
UserService,
|
|
||||||
JobService,
|
JobService,
|
||||||
ConfigService
|
ConfigService
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
export * from './shared'
|
|
||||||
export * from './user-edit'
|
export * from './user-edit'
|
||||||
export * from './user-list'
|
export * from './user-list'
|
||||||
export * from './users.component'
|
export * from './users.component'
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './user.service'
|
|
|
@ -1,96 +0,0 @@
|
||||||
import { catchError, map } from 'rxjs/operators'
|
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
|
||||||
import { Injectable } from '@angular/core'
|
|
||||||
import { BytesPipe } from 'ngx-pipes'
|
|
||||||
import { SortMeta } from 'primeng/components/common/sortmeta'
|
|
||||||
import { Observable } from 'rxjs'
|
|
||||||
import { ResultList, UserCreate, UserUpdate, User, UserRole } from '../../../../../../shared'
|
|
||||||
import { environment } from '../../../../environments/environment'
|
|
||||||
import { RestExtractor, RestPagination, RestService } from '../../../shared'
|
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UserService {
|
|
||||||
private static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/'
|
|
||||||
private bytesPipe = new BytesPipe()
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private authHttp: HttpClient,
|
|
||||||
private restService: RestService,
|
|
||||||
private restExtractor: RestExtractor,
|
|
||||||
private i18n: I18n
|
|
||||||
) { }
|
|
||||||
|
|
||||||
addUser (userCreate: UserCreate) {
|
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
|
|
||||||
.pipe(
|
|
||||||
map(this.restExtractor.extractDataBool),
|
|
||||||
catchError(err => this.restExtractor.handleError(err))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUser (userId: number, userUpdate: UserUpdate) {
|
|
||||||
return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
|
|
||||||
.pipe(
|
|
||||||
map(this.restExtractor.extractDataBool),
|
|
||||||
catchError(err => this.restExtractor.handleError(err))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser (userId: number) {
|
|
||||||
return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId)
|
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> {
|
|
||||||
let params = new HttpParams()
|
|
||||||
params = this.restService.addRestGetParams(params, pagination, sort)
|
|
||||||
|
|
||||||
return this.authHttp.get<ResultList<User>>(UserService.BASE_USERS_URL, { params })
|
|
||||||
.pipe(
|
|
||||||
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
|
||||||
map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
|
|
||||||
catchError(err => this.restExtractor.handleError(err))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
removeUser (user: User) {
|
|
||||||
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
|
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
banUser (user: User, reason?: string) {
|
|
||||||
const body = reason ? { reason } : {}
|
|
||||||
|
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/block', body)
|
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
unbanUser (user: User) {
|
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/unblock', {})
|
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
private formatUser (user: User) {
|
|
||||||
let videoQuota
|
|
||||||
if (user.videoQuota === -1) {
|
|
||||||
videoQuota = this.i18n('Unlimited')
|
|
||||||
} else {
|
|
||||||
videoQuota = this.bytesPipe.transform(user.videoQuota, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const videoQuotaUsed = this.bytesPipe.transform(user.videoQuotaUsed, 0)
|
|
||||||
|
|
||||||
const roleLabels: { [ id in UserRole ]: string } = {
|
|
||||||
[UserRole.USER]: this.i18n('User'),
|
|
||||||
[UserRole.ADMINISTRATOR]: this.i18n('Administrator'),
|
|
||||||
[UserRole.MODERATOR]: this.i18n('Moderator')
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.assign(user, {
|
|
||||||
roleLabel: roleLabels[user.role],
|
|
||||||
videoQuota,
|
|
||||||
videoQuotaUsed
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { UserService } from '../shared'
|
|
||||||
import { ServerService } from '../../../core'
|
import { ServerService } from '../../../core'
|
||||||
import { UserCreate, UserRole } from '../../../../../../shared'
|
import { UserCreate, UserRole } from '../../../../../../shared'
|
||||||
import { UserEdit } from './user-edit'
|
import { UserEdit } from './user-edit'
|
||||||
|
@ -9,6 +8,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
|
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
|
||||||
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
||||||
|
import { UserService } from '@app/shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-user-create',
|
selector: 'my-user-create',
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { UserService } from '../shared'
|
|
||||||
import { ServerService } from '../../../core'
|
import { ServerService } from '../../../core'
|
||||||
import { UserEdit } from './user-edit'
|
import { UserEdit } from './user-edit'
|
||||||
import { User, UserUpdate } from '../../../../../../shared'
|
import { User, UserUpdate } from '../../../../../../shared'
|
||||||
|
@ -10,6 +9,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
|
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
|
||||||
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
||||||
|
import { UserService } from '@app/shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-user-update',
|
selector: 'my-user-update',
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<td>{{ user.roleLabel }}</td>
|
<td>{{ user.roleLabel }}</td>
|
||||||
<td>{{ user.createdAt }}</td>
|
<td>{{ user.createdAt }}</td>
|
||||||
<td class="action-cell">
|
<td class="action-cell">
|
||||||
<my-action-dropdown i18n-label label="Actions" [actions]="userActions" [entry]="user"></my-action-dropdown>
|
<my-user-moderation-dropdown [user]="user" (userChanged)="onUserChanged()"></my-user-moderation-dropdown>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -55,4 +55,3 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
|
|
||||||
<my-user-ban-modal #userBanModal (userBanned)="onUserBanned()"></my-user-ban-modal>
|
|
|
@ -1,13 +1,9 @@
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { SortMeta } from 'primeng/components/common/sortmeta'
|
import { SortMeta } from 'primeng/components/common/sortmeta'
|
||||||
import { ConfirmService } from '../../../core'
|
import { ConfirmService } from '../../../core'
|
||||||
import { RestPagination, RestTable } from '../../../shared'
|
import { RestPagination, RestTable, UserService } from '../../../shared'
|
||||||
import { UserService } from '../shared'
|
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
|
|
||||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
|
||||||
import { UserBanModalComponent } from '@app/+admin/users/user-list/user-ban-modal.component'
|
|
||||||
import { User } from '../../../../../../shared'
|
import { User } from '../../../../../../shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -16,16 +12,11 @@ import { User } from '../../../../../../shared'
|
||||||
styleUrls: [ './user-list.component.scss' ]
|
styleUrls: [ './user-list.component.scss' ]
|
||||||
})
|
})
|
||||||
export class UserListComponent extends RestTable implements OnInit {
|
export class UserListComponent extends RestTable implements OnInit {
|
||||||
@ViewChild('userBanModal') userBanModal: UserBanModalComponent
|
|
||||||
|
|
||||||
users: User[] = []
|
users: User[] = []
|
||||||
totalRecords = 0
|
totalRecords = 0
|
||||||
rowsPerPage = 10
|
rowsPerPage = 10
|
||||||
sort: SortMeta = { field: 'createdAt', order: 1 }
|
sort: SortMeta = { field: 'createdAt', order: 1 }
|
||||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
userActions: DropdownAction<User>[] = []
|
|
||||||
|
|
||||||
private openedModal: NgbModalRef
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
|
@ -34,96 +25,16 @@ export class UserListComponent extends RestTable implements OnInit {
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.userActions = [
|
|
||||||
{
|
|
||||||
label: this.i18n('Edit'),
|
|
||||||
linkBuilder: this.getRouterUserEditLink
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.i18n('Delete'),
|
|
||||||
handler: user => this.removeUser(user)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.i18n('Ban'),
|
|
||||||
handler: user => this.openBanUserModal(user),
|
|
||||||
isDisplayed: user => !user.blocked
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.i18n('Unban'),
|
|
||||||
handler: user => this.unbanUser(user),
|
|
||||||
isDisplayed: user => user.blocked
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.loadSort()
|
this.loadSort()
|
||||||
}
|
}
|
||||||
|
|
||||||
hideBanUserModal () {
|
onUserChanged () {
|
||||||
this.openedModal.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
openBanUserModal (user: User) {
|
|
||||||
if (user.username === 'root') {
|
|
||||||
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userBanModal.openModal(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
onUserBanned () {
|
|
||||||
this.loadData()
|
this.loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
async unbanUser (user: User) {
|
|
||||||
const message = this.i18n('Do you really want to unban {{username}}?', { username: user.username })
|
|
||||||
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
|
|
||||||
if (res === false) return
|
|
||||||
|
|
||||||
this.userService.unbanUser(user)
|
|
||||||
.subscribe(
|
|
||||||
() => {
|
|
||||||
this.notificationsService.success(
|
|
||||||
this.i18n('Success'),
|
|
||||||
this.i18n('User {{username}} unbanned.', { username: user.username })
|
|
||||||
)
|
|
||||||
this.loadData()
|
|
||||||
},
|
|
||||||
|
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeUser (user: User) {
|
|
||||||
if (user.username === 'root') {
|
|
||||||
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot delete root.'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = this.i18n('If you remove this user, you will not be able to create another with the same username!')
|
|
||||||
const res = await this.confirmService.confirm(message, this.i18n('Delete'))
|
|
||||||
if (res === false) return
|
|
||||||
|
|
||||||
this.userService.removeUser(user).subscribe(
|
|
||||||
() => {
|
|
||||||
this.notificationsService.success(
|
|
||||||
this.i18n('Success'),
|
|
||||||
this.i18n('User {{username}} deleted.', { username: user.username })
|
|
||||||
)
|
|
||||||
this.loadData()
|
|
||||||
},
|
|
||||||
|
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
getRouterUserEditLink (user: User) {
|
|
||||||
return [ '/admin', 'users', 'update', user.id ]
|
|
||||||
}
|
|
||||||
|
|
||||||
protected loadData () {
|
protected loadData () {
|
||||||
this.userService.getUsers(this.pagination, this.sort)
|
this.userService.getUsers(this.pagination, this.sort)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './user-ban-modal.component'
|
||||||
|
export * from './user-moderation-dropdown.component'
|
|
@ -1,12 +1,11 @@
|
||||||
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
|
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { FormReactive, UserValidatorsService } from '../../../shared'
|
|
||||||
import { UserService } from '../shared'
|
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { User } from '../../../../../../shared'
|
import { FormReactive, UserValidatorsService } from '@app/shared/forms'
|
||||||
|
import { User, UserService } from '@app/shared/users'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-user-ban-modal',
|
selector: 'my-user-ban-modal',
|
|
@ -0,0 +1,3 @@
|
||||||
|
<my-user-ban-modal #userBanModal (userBanned)="onUserBanned()"></my-user-ban-modal>
|
||||||
|
|
||||||
|
<my-action-dropdown i18n-label label="Actions" [actions]="userActions" [entry]="user"></my-action-dropdown>
|
|
@ -0,0 +1,128 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
||||||
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
|
||||||
|
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||||
|
import { UserBanModalComponent } from '@app/shared/moderation/user-ban-modal.component'
|
||||||
|
import { User, UserService } from '@app/shared/users'
|
||||||
|
import { AuthService, ConfirmService } from '@app/core'
|
||||||
|
import { UserRight } from '../../../../../shared/models/users'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-user-moderation-dropdown',
|
||||||
|
templateUrl: './user-moderation-dropdown.component.html',
|
||||||
|
styleUrls: [ './user-moderation-dropdown.component.scss' ]
|
||||||
|
})
|
||||||
|
export class UserModerationDropdownComponent implements OnInit {
|
||||||
|
@ViewChild('userBanModal') userBanModal: UserBanModalComponent
|
||||||
|
|
||||||
|
@Input() user: User
|
||||||
|
@Output() userChanged = new EventEmitter()
|
||||||
|
|
||||||
|
userActions: DropdownAction<User>[] = []
|
||||||
|
|
||||||
|
private openedModal: NgbModalRef
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private authService: AuthService,
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private confirmService: ConfirmService,
|
||||||
|
private userService: UserService,
|
||||||
|
private i18n: I18n
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.userActions = []
|
||||||
|
|
||||||
|
if (this.authService.isLoggedIn()) {
|
||||||
|
const authUser = this.authService.getUser()
|
||||||
|
|
||||||
|
if (authUser.hasRight(UserRight.MANAGE_USERS)) {
|
||||||
|
this.userActions = this.userActions.concat([
|
||||||
|
{
|
||||||
|
label: this.i18n('Edit'),
|
||||||
|
linkBuilder: this.getRouterUserEditLink
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Delete'),
|
||||||
|
handler: user => this.removeUser(user)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Ban'),
|
||||||
|
handler: user => this.openBanUserModal(user),
|
||||||
|
isDisplayed: user => !user.blocked
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Unban'),
|
||||||
|
handler: user => this.unbanUser(user),
|
||||||
|
isDisplayed: user => user.blocked
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideBanUserModal () {
|
||||||
|
this.openedModal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
openBanUserModal (user: User) {
|
||||||
|
if (user.username === 'root') {
|
||||||
|
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userBanModal.openModal(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserBanned () {
|
||||||
|
this.userChanged.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
async unbanUser (user: User) {
|
||||||
|
const message = this.i18n('Do you really want to unban {{username}}?', { username: user.username })
|
||||||
|
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.userService.unbanUser(user)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('User {{username}} unbanned.', { username: user.username })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeUser (user: User) {
|
||||||
|
if (user.username === 'root') {
|
||||||
|
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot delete root.'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = this.i18n('If you remove this user, you will not be able to create another with the same username!')
|
||||||
|
const res = await this.confirmService.confirm(message, this.i18n('Delete'))
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.userService.removeUser(user).subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('User {{username}} deleted.', { username: user.username })
|
||||||
|
)
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getRouterUserEditLink (user: User) {
|
||||||
|
return [ '/admin', 'users', 'update', user.id ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,8 @@ import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, N
|
||||||
import { SubscribeButtonComponent, RemoteSubscribeComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
import { SubscribeButtonComponent, RemoteSubscribeComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
||||||
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
||||||
import { OverviewService } from '@app/shared/overview'
|
import { OverviewService } from '@app/shared/overview'
|
||||||
|
import { UserBanModalComponent } from '@app/shared/moderation'
|
||||||
|
import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -94,7 +96,9 @@ import { OverviewService } from '@app/shared/overview'
|
||||||
PeertubeCheckboxComponent,
|
PeertubeCheckboxComponent,
|
||||||
SubscribeButtonComponent,
|
SubscribeButtonComponent,
|
||||||
RemoteSubscribeComponent,
|
RemoteSubscribeComponent,
|
||||||
InstanceFeaturesTableComponent
|
InstanceFeaturesTableComponent,
|
||||||
|
UserBanModalComponent,
|
||||||
|
UserModerationDropdownComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -130,6 +134,8 @@ import { OverviewService } from '@app/shared/overview'
|
||||||
SubscribeButtonComponent,
|
SubscribeButtonComponent,
|
||||||
RemoteSubscribeComponent,
|
RemoteSubscribeComponent,
|
||||||
InstanceFeaturesTableComponent,
|
InstanceFeaturesTableComponent,
|
||||||
|
UserBanModalComponent,
|
||||||
|
UserModerationDropdownComponent,
|
||||||
|
|
||||||
NumberFormatterPipe,
|
NumberFormatterPipe,
|
||||||
ObjectLengthPipe,
|
ObjectLengthPipe,
|
||||||
|
|
|
@ -2,20 +2,26 @@ import { Observable } from 'rxjs'
|
||||||
import { catchError, map } from 'rxjs/operators'
|
import { catchError, map } from 'rxjs/operators'
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { UserCreate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
|
import { ResultList, User, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { RestExtractor } from '../rest'
|
import { RestExtractor, RestPagination, RestService } from '../rest'
|
||||||
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
|
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
|
||||||
|
import { SortMeta } from 'primeng/api'
|
||||||
|
import { BytesPipe } from 'ngx-pipes'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/'
|
static BASE_USERS_URL = environment.apiUrl + '/api/v1/users/'
|
||||||
|
|
||||||
|
private bytesPipe = new BytesPipe()
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: HttpClient,
|
private authHttp: HttpClient,
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor,
|
||||||
) {
|
private restService: RestService,
|
||||||
}
|
private i18n: I18n
|
||||||
|
) { }
|
||||||
|
|
||||||
changePassword (currentPassword: string, newPassword: string) {
|
changePassword (currentPassword: string, newPassword: string) {
|
||||||
const url = UserService.BASE_USERS_URL + 'me'
|
const url = UserService.BASE_USERS_URL + 'me'
|
||||||
|
@ -128,4 +134,79 @@ export class UserService {
|
||||||
.get<string[]>(url, { params })
|
.get<string[]>(url, { params })
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ###### Admin methods ###### */
|
||||||
|
|
||||||
|
addUser (userCreate: UserCreate) {
|
||||||
|
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
|
||||||
|
.pipe(
|
||||||
|
map(this.restExtractor.extractDataBool),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUser (userId: number, userUpdate: UserUpdate) {
|
||||||
|
return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
|
||||||
|
.pipe(
|
||||||
|
map(this.restExtractor.extractDataBool),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser (userId: number) {
|
||||||
|
return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> {
|
||||||
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<User>>(UserService.BASE_USERS_URL, { params })
|
||||||
|
.pipe(
|
||||||
|
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
||||||
|
map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeUser (user: User) {
|
||||||
|
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
banUser (user: User, reason?: string) {
|
||||||
|
const body = reason ? { reason } : {}
|
||||||
|
|
||||||
|
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/block', body)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
unbanUser (user: User) {
|
||||||
|
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/unblock', {})
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatUser (user: User) {
|
||||||
|
let videoQuota
|
||||||
|
if (user.videoQuota === -1) {
|
||||||
|
videoQuota = this.i18n('Unlimited')
|
||||||
|
} else {
|
||||||
|
videoQuota = this.bytesPipe.transform(user.videoQuota, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoQuotaUsed = this.bytesPipe.transform(user.videoQuotaUsed, 0)
|
||||||
|
|
||||||
|
const roleLabels: { [ id in UserRole ]: string } = {
|
||||||
|
[UserRole.USER]: this.i18n('User'),
|
||||||
|
[UserRole.ADMINISTRATOR]: this.i18n('Administrator'),
|
||||||
|
[UserRole.MODERATOR]: this.i18n('Moderator')
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(user, {
|
||||||
|
roleLabel: roleLabels[user.role],
|
||||||
|
videoQuota,
|
||||||
|
videoQuotaUsed
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue