From cd940f40cb62fa105b14e1ce838e97f316c13c5c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 20 Jan 2023 14:58:05 +0100 Subject: [PATCH] Support bulk registration request removal --- .../followers-list.component.html | 4 +- .../followers-list.component.ts | 17 +++---- .../following-list.component.html | 4 +- .../following-list.component.ts | 11 ++--- .../admin-registration.service.ts | 16 +++++-- .../registration-list.component.html | 19 +++++++- .../registration-list.component.ts | 46 +++++++++++++++---- .../video-comment-list.component.html | 4 +- .../comments/video-comment-list.component.ts | 13 ++---- .../users/user-list/user-list.component.html | 4 +- .../users/user-list/user-list.component.ts | 15 ++---- .../overview/videos/video-list.component.html | 4 +- .../overview/videos/video-list.component.ts | 14 ++---- .../app/core/renderer/linkifier.service.ts | 2 +- client/src/app/core/rest/rest-table.ts | 8 +++- .../user-moderation-dropdown.component.ts | 2 +- .../shared/shared-users/user-admin.service.ts | 2 +- 17 files changed, 107 insertions(+), 78 deletions(-) diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 8fe0d2348..14c62f1af 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html @@ -9,14 +9,14 @@ [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [showCurrentPageReport]="true" i18n-currentPageReportTemplate currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers" - [(selection)]="selectedFollows" + [(selection)]="selectedRows" >
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts index b2d333e83..6dd64fc57 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts @@ -12,7 +12,7 @@ import { ActorFollow } from '@shared/models' templateUrl: './followers-list.component.html', styleUrls: [ './followers-list.component.scss' ] }) -export class FollowersListComponent extends RestTable implements OnInit { +export class FollowersListComponent extends RestTable implements OnInit { followers: ActorFollow[] = [] totalRecords = 0 sort: SortMeta = { field: 'createdAt', order: -1 } @@ -20,8 +20,7 @@ export class FollowersListComponent extends RestTable implements OnInit { searchFilters: AdvancedInputFilter[] = [] - selectedFollows: ActorFollow[] = [] - bulkFollowsActions: DropdownAction[] = [] + bulkActions: DropdownAction[] = [] constructor ( private confirmService: ConfirmService, @@ -36,7 +35,7 @@ export class FollowersListComponent extends RestTable implements OnInit { this.searchFilters = this.followService.buildFollowsListFilters() - this.bulkFollowsActions = [ + this.bulkActions = [ { label: $localize`Reject`, handler: follows => this.rejectFollower(follows), @@ -105,12 +104,14 @@ export class FollowersListComponent extends RestTable implements OnInit { } async deleteFollowers (follows: ActorFollow[]) { + const icuParams = { count: follows.length, followerName: this.buildFollowerName(follows[0]) } + let message = $localize`Deleted followers will be able to send again a follow request.` message += '

' // eslint-disable-next-line max-len message += prepareIcu($localize`Do you really want to delete {count, plural, =1 {{followerName} follow request?} other {{count} follow requests?}}`)( - { count: follows.length, followerName: this.buildFollowerName(follows[0]) }, + icuParams, $localize`Do you really want to delete these follow requests?` ) @@ -122,7 +123,7 @@ export class FollowersListComponent extends RestTable implements OnInit { next: () => { // eslint-disable-next-line max-len const message = prepareIcu($localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)( - { count: follows.length, followerName: this.buildFollowerName(follows[0]) }, + icuParams, $localize`Follow requests removed` ) @@ -139,10 +140,6 @@ export class FollowersListComponent extends RestTable implements OnInit { return follow.follower.name + '@' + follow.follower.host } - isInSelectionMode () { - return this.selectedFollows.length !== 0 - } - protected reloadData () { this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) .subscribe({ diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index f7abb7ede..eca79be71 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html @@ -9,14 +9,14 @@ [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [showCurrentPageReport]="true" i18n-currentPageReportTemplate currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts" - [(selection)]="selectedFollows" + [(selection)]="selectedRows" >
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts index e3a56651a..e986a610a 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.ts +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts @@ -12,7 +12,7 @@ import { prepareIcu } from '@app/helpers' templateUrl: './following-list.component.html', styleUrls: [ './following-list.component.scss' ] }) -export class FollowingListComponent extends RestTable implements OnInit { +export class FollowingListComponent extends RestTable implements OnInit { @ViewChild('followModal') followModal: FollowModalComponent following: ActorFollow[] = [] @@ -22,8 +22,7 @@ export class FollowingListComponent extends RestTable implements OnInit { searchFilters: AdvancedInputFilter[] = [] - selectedFollows: ActorFollow[] = [] - bulkFollowsActions: DropdownAction[] = [] + bulkActions: DropdownAction[] = [] constructor ( private notifier: Notifier, @@ -38,7 +37,7 @@ export class FollowingListComponent extends RestTable implements OnInit { this.searchFilters = this.followService.buildFollowsListFilters() - this.bulkFollowsActions = [ + this.bulkActions = [ { label: $localize`Delete`, handler: follows => this.removeFollowing(follows) @@ -58,10 +57,6 @@ export class FollowingListComponent extends RestTable implements OnInit { return follow.following.name === 'peertube' } - isInSelectionMode () { - return this.selectedFollows.length !== 0 - } - buildFollowingName (follow: ActorFollow) { return follow.following.name + '@' + follow.following.host } diff --git a/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts b/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts index 012f942b3..10e2938c7 100644 --- a/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts +++ b/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts @@ -1,8 +1,10 @@ import { SortMeta } from 'primeng/api' -import { catchError } from 'rxjs/operators' +import { from } from 'rxjs' +import { catchError, concatMap, toArray } from 'rxjs/operators' import { HttpClient, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { RestExtractor, RestPagination, RestService } from '@app/core' +import { arrayify } from '@shared/core-utils' import { ResultList, UserRegistration } from '@shared/models' import { environment } from '../../../../environments/environment' @@ -54,10 +56,14 @@ export class AdminRegistrationService { .pipe(catchError(res => this.restExtractor.handleError(res))) } - removeRegistration (registration: UserRegistration) { - const url = AdminRegistrationService.BASE_REGISTRATION_URL + '/' + registration.id + removeRegistrations (registrationsArg: UserRegistration | UserRegistration[]) { + const registrations = arrayify(registrationsArg) - return this.authHttp.delete(url) - .pipe(catchError(res => this.restExtractor.handleError(res))) + return from(registrations) + .pipe( + concatMap(r => this.authHttp.delete(AdminRegistrationService.BASE_REGISTRATION_URL + '/' + r.id)), + toArray(), + catchError(err => this.restExtractor.handleError(err)) + ) } } diff --git a/client/src/app/+admin/moderation/registration-list/registration-list.component.html b/client/src/app/+admin/moderation/registration-list/registration-list.component.html index 4f9d06acc..a2b888101 100644 --- a/client/src/app/+admin/moderation/registration-list/registration-list.component.html +++ b/client/src/app/+admin/moderation/registration-list/registration-list.component.html @@ -7,12 +7,20 @@ [value]="registrations" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" - [showCurrentPageReport]="true" i18n-currentPageReportTemplate + [(selection)]="selectedRows" [showCurrentPageReport]="true" i18n-currentPageReportTemplate currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} registrations" [expandedRowKeys]="expandedRows" >
+
+ + +
+
@@ -21,6 +29,9 @@ + + + Account @@ -34,7 +45,11 @@ - + + + + + diff --git a/client/src/app/+admin/moderation/registration-list/registration-list.component.ts b/client/src/app/+admin/moderation/registration-list/registration-list.component.ts index 37514edf5..569eccaa2 100644 --- a/client/src/app/+admin/moderation/registration-list/registration-list.component.ts +++ b/client/src/app/+admin/moderation/registration-list/registration-list.component.ts @@ -1,7 +1,8 @@ import { SortMeta } from 'primeng/api' import { Component, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' +import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' +import { prepareIcu } from '@app/helpers' import { AdvancedInputFilter } from '@app/shared/shared-forms' import { DropdownAction } from '@app/shared/shared-main' import { UserRegistration, UserRegistrationState } from '@shared/models' @@ -13,7 +14,7 @@ import { ProcessRegistrationModalComponent } from './process-registration-modal. templateUrl: './registration-list.component.html', styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './registration-list.component.scss' ] }) -export class RegistrationListComponent extends RestTable implements OnInit { +export class RegistrationListComponent extends RestTable implements OnInit { @ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = [] @@ -22,6 +23,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { pagination: RestPagination = { count: this.rowsPerPage, start: 0 } registrationActions: DropdownAction[][] = [] + bulkActions: DropdownAction[] = [] inputFilters: AdvancedInputFilter[] = [] @@ -33,6 +35,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { private server: ServerService, private notifier: Notifier, private markdownRenderer: MarkdownService, + private confirmService: ConfirmService, private adminRegistrationService: AdminRegistrationService ) { super() @@ -40,22 +43,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { this.registrationActions = [ [ { - label: $localize`Accept this registration`, + label: $localize`Accept this request`, handler: registration => this.openRegistrationRequestProcessModal(registration, 'accept'), isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING }, { - label: $localize`Reject this registration`, + label: $localize`Reject this request`, handler: registration => this.openRegistrationRequestProcessModal(registration, 'reject'), isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING }, { - label: $localize`Remove this registration request`, - handler: registration => this.removeRegistration(registration), - isDisplayed: registration => registration.state.id !== UserRegistrationState.PENDING + label: $localize`Remove this request`, + handler: registration => this.removeRegistrations([ registration ]) } ] ] + + this.bulkActions = [ + { + label: $localize`Delete`, + handler: registrations => this.removeRegistrations(registrations) + } + ] } ngOnInit () { @@ -107,11 +116,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { this.processRegistrationModal.openModal(registration, mode) } - private removeRegistration (registration: UserRegistration) { - this.adminRegistrationService.removeRegistration(registration) + private async removeRegistrations (registrations: UserRegistration[]) { + const icuParams = { count: registrations.length, username: registrations[0].username } + + // eslint-disable-next-line max-len + const message = prepareIcu($localize`Do you really want to delete {count, plural, =1 {{username} registration request?} other {{count} registration requests?}}`)( + icuParams, + $localize`Do you really want to delete these registration requests?` + ) + + const res = await this.confirmService.confirm(message, $localize`Delete`) + if (res === false) return + + this.adminRegistrationService.removeRegistrations(registrations) .subscribe({ next: () => { - this.notifier.success($localize`Registration request deleted.`) + // eslint-disable-next-line max-len + const message = prepareIcu($localize`Removed {count, plural, =1 {{username} registration request} other {{count} registration requests}}`)( + icuParams, + $localize`Registration requests removed` + ) + + this.notifier.success(message) this.reloadData() }, diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.html b/client/src/app/+admin/overview/comments/video-comment-list.component.html index d2ca5f700..b0d8131bf 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.html +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.html @@ -13,14 +13,14 @@ [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" [showCurrentPageReport]="true" i18n-currentPageReportTemplate currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" - [expandedRowKeys]="expandedRows" [(selection)]="selectedComments" + [expandedRowKeys]="expandedRows" [(selection)]="selectedRows" >
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.ts b/client/src/app/+admin/overview/comments/video-comment-list.component.ts index c95d2ffeb..cfa68ed9d 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.ts +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.ts @@ -14,7 +14,7 @@ import { prepareIcu } from '@app/helpers' templateUrl: './video-comment-list.component.html', styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-comment-list.component.scss' ] }) -export class VideoCommentListComponent extends RestTable implements OnInit { +export class VideoCommentListComponent extends RestTable implements OnInit { comments: VideoCommentAdmin[] totalRecords = 0 sort: SortMeta = { field: 'createdAt', order: -1 } @@ -40,8 +40,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { } ] - selectedComments: VideoCommentAdmin[] = [] - bulkCommentActions: DropdownAction[] = [] + bulkActions: DropdownAction[] = [] inputFilters: AdvancedInputFilter[] = [ { @@ -100,7 +99,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { ngOnInit () { this.initialize() - this.bulkCommentActions = [ + this.bulkActions = [ { label: $localize`Delete`, handler: comments => this.removeComments(comments), @@ -118,10 +117,6 @@ export class VideoCommentListComponent extends RestTable implements OnInit { return this.markdownRenderer.textMarkdownToHTML({ markdown: text, withHtml: true, withEmoji: true }) } - isInSelectionMode () { - return this.selectedComments.length !== 0 - } - reloadData () { this.videoCommentService.getAdminVideoComments({ pagination: this.pagination, @@ -162,7 +157,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { error: err => this.notifier.error(err.message), - complete: () => this.selectedComments = [] + complete: () => this.selectedRows = [] }) } diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index 5e5ac368c..7eb5e0fc7 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html @@ -6,7 +6,7 @@ diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.ts b/client/src/app/+admin/overview/users/user-list/user-list.component.ts index 99987fdff..7d62302f8 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.ts @@ -22,7 +22,7 @@ type UserForList = User & { templateUrl: './user-list.component.html', styleUrls: [ './user-list.component.scss' ] }) -export class UserListComponent extends RestTable implements OnInit { +export class UserListComponent extends RestTable implements OnInit { private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns' @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent @@ -35,8 +35,7 @@ export class UserListComponent extends RestTable implements OnInit { highlightBannedUsers = false - selectedUsers: User[] = [] - bulkUserActions: DropdownAction[][] = [] + bulkActions: DropdownAction[][] = [] columns: { id: string, label: string }[] inputFilters: AdvancedInputFilter[] = [ @@ -95,7 +94,7 @@ export class UserListComponent extends RestTable implements OnInit { this.initialize() - this.bulkUserActions = [ + this.bulkActions = [ [ { label: $localize`Delete`, @@ -249,7 +248,7 @@ export class UserListComponent extends RestTable implements OnInit { const res = await this.confirmService.confirm(message, $localize`Delete`) if (res === false) return - this.userAdminService.removeUser(users) + this.userAdminService.removeUsers(users) .subscribe({ next: () => { this.notifier.success( @@ -284,12 +283,8 @@ export class UserListComponent extends RestTable implements OnInit { }) } - isInSelectionMode () { - return this.selectedUsers.length !== 0 - } - protected reloadData () { - this.selectedUsers = [] + this.selectedRows = [] this.userAdminService.getUsers({ pagination: this.pagination, diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index a6cd2e257..5b8405ad9 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html @@ -6,7 +6,7 @@
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index 4d3e9873c..cd5d2eb34 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts @@ -17,7 +17,7 @@ import { VideoAdminService } from './video-admin.service' templateUrl: './video-list.component.html', styleUrls: [ './video-list.component.scss' ] }) -export class VideoListComponent extends RestTable implements OnInit { +export class VideoListComponent extends RestTable