diff options
Diffstat (limited to 'client/src/app/+admin/moderation')
3 files changed, 64 insertions, 17 deletions
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 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { catchError } from 'rxjs/operators' | 2 | import { from } from 'rxjs' |
3 | import { catchError, concatMap, toArray } from 'rxjs/operators' | ||
3 | import { HttpClient, HttpParams } from '@angular/common/http' | 4 | import { HttpClient, HttpParams } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 5 | import { Injectable } from '@angular/core' |
5 | import { RestExtractor, RestPagination, RestService } from '@app/core' | 6 | import { RestExtractor, RestPagination, RestService } from '@app/core' |
7 | import { arrayify } from '@shared/core-utils' | ||
6 | import { ResultList, UserRegistration } from '@shared/models' | 8 | import { ResultList, UserRegistration } from '@shared/models' |
7 | import { environment } from '../../../../environments/environment' | 9 | import { environment } from '../../../../environments/environment' |
8 | 10 | ||
@@ -54,10 +56,14 @@ export class AdminRegistrationService { | |||
54 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 56 | .pipe(catchError(res => this.restExtractor.handleError(res))) |
55 | } | 57 | } |
56 | 58 | ||
57 | removeRegistration (registration: UserRegistration) { | 59 | removeRegistrations (registrationsArg: UserRegistration | UserRegistration[]) { |
58 | const url = AdminRegistrationService.BASE_REGISTRATION_URL + '/' + registration.id | 60 | const registrations = arrayify(registrationsArg) |
59 | 61 | ||
60 | return this.authHttp.delete(url) | 62 | return from(registrations) |
61 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 63 | .pipe( |
64 | concatMap(r => this.authHttp.delete(AdminRegistrationService.BASE_REGISTRATION_URL + '/' + r.id)), | ||
65 | toArray(), | ||
66 | catchError(err => this.restExtractor.handleError(err)) | ||
67 | ) | ||
62 | } | 68 | } |
63 | } | 69 | } |
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 @@ | |||
7 | [value]="registrations" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" | 7 | [value]="registrations" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" |
8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" | 8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | 9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [(selection)]="selectedRows" [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} registrations" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} registrations" |
12 | [expandedRowKeys]="expandedRows" | 12 | [expandedRowKeys]="expandedRows" |
13 | > | 13 | > |
14 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
15 | <div class="caption"> | 15 | <div class="caption"> |
16 | <div class="left-buttons"> | ||
17 | <my-action-dropdown | ||
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | ||
19 | [actions]="bulkActions" [entry]="selectedRows" | ||
20 | > | ||
21 | </my-action-dropdown> | ||
22 | </div> | ||
23 | |||
16 | <div class="ms-auto"> | 24 | <div class="ms-auto"> |
17 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 25 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
18 | </div> | 26 | </div> |
@@ -21,6 +29,9 @@ | |||
21 | 29 | ||
22 | <ng-template pTemplate="header"> | 30 | <ng-template pTemplate="header"> |
23 | <tr> <!-- header --> | 31 | <tr> <!-- header --> |
32 | <th style="width: 40px"> | ||
33 | <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox> | ||
34 | </th> | ||
24 | <th style="width: 40px;"></th> | 35 | <th style="width: 40px;"></th> |
25 | <th style="width: 150px;"></th> | 36 | <th style="width: 150px;"></th> |
26 | <th i18n>Account</th> | 37 | <th i18n>Account</th> |
@@ -34,7 +45,11 @@ | |||
34 | </ng-template> | 45 | </ng-template> |
35 | 46 | ||
36 | <ng-template pTemplate="body" let-expanded="expanded" let-registration> | 47 | <ng-template pTemplate="body" let-expanded="expanded" let-registration> |
37 | <tr> | 48 | <tr [pSelectableRow]="registration"> |
49 | <td class="checkbox-cell"> | ||
50 | <p-tableCheckbox [value]="registration" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox> | ||
51 | </td> | ||
52 | |||
38 | <td class="expand-cell" [pRowToggler]="registration"> | 53 | <td class="expand-cell" [pRowToggler]="registration"> |
39 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> | 54 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> |
40 | </td> | 55 | </td> |
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 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { Component, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, OnInit, ViewChild } from '@angular/core' |
3 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 4 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
5 | import { prepareIcu } from '@app/helpers' | ||
5 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
6 | import { DropdownAction } from '@app/shared/shared-main' | 7 | import { DropdownAction } from '@app/shared/shared-main' |
7 | import { UserRegistration, UserRegistrationState } from '@shared/models' | 8 | import { UserRegistration, UserRegistrationState } from '@shared/models' |
@@ -13,7 +14,7 @@ import { ProcessRegistrationModalComponent } from './process-registration-modal. | |||
13 | templateUrl: './registration-list.component.html', | 14 | templateUrl: './registration-list.component.html', |
14 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './registration-list.component.scss' ] | 15 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './registration-list.component.scss' ] |
15 | }) | 16 | }) |
16 | export class RegistrationListComponent extends RestTable implements OnInit { | 17 | export class RegistrationListComponent extends RestTable <UserRegistration> implements OnInit { |
17 | @ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent | 18 | @ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent |
18 | 19 | ||
19 | registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = [] | 20 | registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = [] |
@@ -22,6 +23,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
22 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 23 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
23 | 24 | ||
24 | registrationActions: DropdownAction<UserRegistration>[][] = [] | 25 | registrationActions: DropdownAction<UserRegistration>[][] = [] |
26 | bulkActions: DropdownAction<UserRegistration[]>[] = [] | ||
25 | 27 | ||
26 | inputFilters: AdvancedInputFilter[] = [] | 28 | inputFilters: AdvancedInputFilter[] = [] |
27 | 29 | ||
@@ -33,6 +35,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
33 | private server: ServerService, | 35 | private server: ServerService, |
34 | private notifier: Notifier, | 36 | private notifier: Notifier, |
35 | private markdownRenderer: MarkdownService, | 37 | private markdownRenderer: MarkdownService, |
38 | private confirmService: ConfirmService, | ||
36 | private adminRegistrationService: AdminRegistrationService | 39 | private adminRegistrationService: AdminRegistrationService |
37 | ) { | 40 | ) { |
38 | super() | 41 | super() |
@@ -40,22 +43,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
40 | this.registrationActions = [ | 43 | this.registrationActions = [ |
41 | [ | 44 | [ |
42 | { | 45 | { |
43 | label: $localize`Accept this registration`, | 46 | label: $localize`Accept this request`, |
44 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'accept'), | 47 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'accept'), |
45 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING | 48 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING |
46 | }, | 49 | }, |
47 | { | 50 | { |
48 | label: $localize`Reject this registration`, | 51 | label: $localize`Reject this request`, |
49 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'reject'), | 52 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'reject'), |
50 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING | 53 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING |
51 | }, | 54 | }, |
52 | { | 55 | { |
53 | label: $localize`Remove this registration request`, | 56 | label: $localize`Remove this request`, |
54 | handler: registration => this.removeRegistration(registration), | 57 | handler: registration => this.removeRegistrations([ registration ]) |
55 | isDisplayed: registration => registration.state.id !== UserRegistrationState.PENDING | ||
56 | } | 58 | } |
57 | ] | 59 | ] |
58 | ] | 60 | ] |
61 | |||
62 | this.bulkActions = [ | ||
63 | { | ||
64 | label: $localize`Delete`, | ||
65 | handler: registrations => this.removeRegistrations(registrations) | ||
66 | } | ||
67 | ] | ||
59 | } | 68 | } |
60 | 69 | ||
61 | ngOnInit () { | 70 | ngOnInit () { |
@@ -107,11 +116,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
107 | this.processRegistrationModal.openModal(registration, mode) | 116 | this.processRegistrationModal.openModal(registration, mode) |
108 | } | 117 | } |
109 | 118 | ||
110 | private removeRegistration (registration: UserRegistration) { | 119 | private async removeRegistrations (registrations: UserRegistration[]) { |
111 | this.adminRegistrationService.removeRegistration(registration) | 120 | const icuParams = { count: registrations.length, username: registrations[0].username } |
121 | |||
122 | // eslint-disable-next-line max-len | ||
123 | const message = prepareIcu($localize`Do you really want to delete {count, plural, =1 {{username} registration request?} other {{count} registration requests?}}`)( | ||
124 | icuParams, | ||
125 | $localize`Do you really want to delete these registration requests?` | ||
126 | ) | ||
127 | |||
128 | const res = await this.confirmService.confirm(message, $localize`Delete`) | ||
129 | if (res === false) return | ||
130 | |||
131 | this.adminRegistrationService.removeRegistrations(registrations) | ||
112 | .subscribe({ | 132 | .subscribe({ |
113 | next: () => { | 133 | next: () => { |
114 | this.notifier.success($localize`Registration request deleted.`) | 134 | // eslint-disable-next-line max-len |
135 | const message = prepareIcu($localize`Removed {count, plural, =1 {{username} registration request} other {{count} registration requests}}`)( | ||
136 | icuParams, | ||
137 | $localize`Registration requests removed` | ||
138 | ) | ||
139 | |||
140 | this.notifier.success(message) | ||
115 | this.reloadData() | 141 | this.reloadData() |
116 | }, | 142 | }, |
117 | 143 | ||