diff options
Diffstat (limited to 'client/src/app/+admin/overview/users/user-list/user-list.component.ts')
-rw-r--r-- | client/src/app/+admin/overview/users/user-list/user-list.component.ts | 91 |
1 files changed, 71 insertions, 20 deletions
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 d22e1355e..f7dc22256 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 | |||
@@ -1,8 +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 { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 4 | import { AuthService, ConfirmService, LocalStorageService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
5 | import { getAPIHost } from '@app/helpers' | 5 | import { prepareIcu, getAPIHost } from '@app/helpers' |
6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
7 | import { Actor, DropdownAction } from '@app/shared/shared-main' | 7 | import { Actor, DropdownAction } from '@app/shared/shared-main' |
8 | import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' | 8 | import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' |
@@ -22,6 +22,8 @@ type UserForList = User & { | |||
22 | styleUrls: [ './user-list.component.scss' ] | 22 | styleUrls: [ './user-list.component.scss' ] |
23 | }) | 23 | }) |
24 | export class UserListComponent extends RestTable implements OnInit { | 24 | export class UserListComponent extends RestTable implements OnInit { |
25 | private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns' | ||
26 | |||
25 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent | 27 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent |
26 | 28 | ||
27 | users: (User & { accountMutedStatus: AccountMutedStatus })[] = [] | 29 | users: (User & { accountMutedStatus: AccountMutedStatus })[] = [] |
@@ -56,7 +58,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
56 | 58 | ||
57 | requiresEmailVerification = false | 59 | requiresEmailVerification = false |
58 | 60 | ||
59 | private _selectedColumns: string[] | 61 | private _selectedColumns: string[] = [] |
60 | 62 | ||
61 | constructor ( | 63 | constructor ( |
62 | protected route: ActivatedRoute, | 64 | protected route: ActivatedRoute, |
@@ -66,7 +68,8 @@ export class UserListComponent extends RestTable implements OnInit { | |||
66 | private serverService: ServerService, | 68 | private serverService: ServerService, |
67 | private auth: AuthService, | 69 | private auth: AuthService, |
68 | private blocklist: BlocklistService, | 70 | private blocklist: BlocklistService, |
69 | private userAdminService: UserAdminService | 71 | private userAdminService: UserAdminService, |
72 | private peertubeLocalStorage: LocalStorageService | ||
70 | ) { | 73 | ) { |
71 | super() | 74 | super() |
72 | } | 75 | } |
@@ -76,11 +79,13 @@ export class UserListComponent extends RestTable implements OnInit { | |||
76 | } | 79 | } |
77 | 80 | ||
78 | get selectedColumns () { | 81 | get selectedColumns () { |
79 | return this._selectedColumns | 82 | return this._selectedColumns || [] |
80 | } | 83 | } |
81 | 84 | ||
82 | set selectedColumns (val: string[]) { | 85 | set selectedColumns (val: string[]) { |
83 | this._selectedColumns = val | 86 | this._selectedColumns = val |
87 | |||
88 | this.saveSelectedColumns() | ||
84 | } | 89 | } |
85 | 90 | ||
86 | ngOnInit () { | 91 | ngOnInit () { |
@@ -126,14 +131,35 @@ export class UserListComponent extends RestTable implements OnInit { | |||
126 | { id: 'role', label: $localize`Role` }, | 131 | { id: 'role', label: $localize`Role` }, |
127 | { id: 'email', label: $localize`Email` }, | 132 | { id: 'email', label: $localize`Email` }, |
128 | { id: 'quota', label: $localize`Video quota` }, | 133 | { id: 'quota', label: $localize`Video quota` }, |
129 | { id: 'createdAt', label: $localize`Created` } | 134 | { id: 'createdAt', label: $localize`Created` }, |
135 | { id: 'lastLoginDate', label: $localize`Last login` }, | ||
136 | |||
137 | { id: 'quotaDaily', label: $localize`Daily quota` }, | ||
138 | { id: 'pluginAuth', label: $localize`Auth plugin` } | ||
130 | ] | 139 | ] |
131 | 140 | ||
132 | this.selectedColumns = this.columns.map(c => c.id) | 141 | this.loadSelectedColumns() |
142 | } | ||
143 | |||
144 | loadSelectedColumns () { | ||
145 | const result = this.peertubeLocalStorage.getItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY) | ||
133 | 146 | ||
134 | this.columns.push({ id: 'quotaDaily', label: $localize`Daily quota` }) | 147 | if (result) { |
135 | this.columns.push({ id: 'pluginAuth', label: $localize`Auth plugin` }) | 148 | try { |
136 | this.columns.push({ id: 'lastLoginDate', label: $localize`Last login` }) | 149 | this.selectedColumns = JSON.parse(result) |
150 | return | ||
151 | } catch (err) { | ||
152 | console.error('Cannot load selected columns.', err) | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Default behaviour | ||
157 | this.selectedColumns = [ 'username', 'role', 'email', 'quota', 'createdAt', 'lastLoginDate' ] | ||
158 | return | ||
159 | } | ||
160 | |||
161 | saveSelectedColumns () { | ||
162 | this.peertubeLocalStorage.setItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY, JSON.stringify(this.selectedColumns)) | ||
137 | } | 163 | } |
138 | 164 | ||
139 | getIdentifier () { | 165 | getIdentifier () { |
@@ -183,13 +209,25 @@ export class UserListComponent extends RestTable implements OnInit { | |||
183 | } | 209 | } |
184 | 210 | ||
185 | async unbanUsers (users: User[]) { | 211 | async unbanUsers (users: User[]) { |
186 | const res = await this.confirmService.confirm($localize`Do you really want to unban ${users.length} users?`, $localize`Unban`) | 212 | const res = await this.confirmService.confirm( |
213 | prepareIcu($localize`Do you really want to unban {count, plural, =1 {1 user} other {{count} users}}?`)( | ||
214 | { count: users.length }, | ||
215 | $localize`Do you really want to unban ${users.length} users?` | ||
216 | ), | ||
217 | $localize`Unban` | ||
218 | ) | ||
219 | |||
187 | if (res === false) return | 220 | if (res === false) return |
188 | 221 | ||
189 | this.userAdminService.unbanUsers(users) | 222 | this.userAdminService.unbanUsers(users) |
190 | .subscribe({ | 223 | .subscribe({ |
191 | next: () => { | 224 | next: () => { |
192 | this.notifier.success($localize`${users.length} users unbanned.`) | 225 | this.notifier.success( |
226 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} unbanned.`)( | ||
227 | { count: users.length }, | ||
228 | $localize`${users.length} users unbanned.` | ||
229 | ) | ||
230 | ) | ||
193 | this.reloadData() | 231 | this.reloadData() |
194 | }, | 232 | }, |
195 | 233 | ||
@@ -198,21 +236,28 @@ export class UserListComponent extends RestTable implements OnInit { | |||
198 | } | 236 | } |
199 | 237 | ||
200 | async removeUsers (users: User[]) { | 238 | async removeUsers (users: User[]) { |
201 | for (const user of users) { | 239 | if (users.some(u => u.username === 'root')) { |
202 | if (user.username === 'root') { | 240 | this.notifier.error($localize`You cannot delete root.`) |
203 | this.notifier.error($localize`You cannot delete root.`) | 241 | return |
204 | return | ||
205 | } | ||
206 | } | 242 | } |
207 | 243 | ||
208 | const message = $localize`If you remove these users, you will not be able to create others with the same username!` | 244 | const message = $localize`<p>You can't create users or channels with a username that already used by a deleted user/channel.</p>` + |
245 | $localize`It means the following usernames will be permanently deleted and cannot be recovered:` + | ||
246 | '<ul>' + users.map(u => '<li>' + u.username + '</li>').join('') + '</ul>' | ||
247 | |||
209 | const res = await this.confirmService.confirm(message, $localize`Delete`) | 248 | const res = await this.confirmService.confirm(message, $localize`Delete`) |
210 | if (res === false) return | 249 | if (res === false) return |
211 | 250 | ||
212 | this.userAdminService.removeUser(users) | 251 | this.userAdminService.removeUser(users) |
213 | .subscribe({ | 252 | .subscribe({ |
214 | next: () => { | 253 | next: () => { |
215 | this.notifier.success($localize`${users.length} users deleted.`) | 254 | this.notifier.success( |
255 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} deleted.`)( | ||
256 | { count: users.length }, | ||
257 | $localize`${users.length} users deleted.` | ||
258 | ) | ||
259 | ) | ||
260 | |||
216 | this.reloadData() | 261 | this.reloadData() |
217 | }, | 262 | }, |
218 | 263 | ||
@@ -224,7 +269,13 @@ export class UserListComponent extends RestTable implements OnInit { | |||
224 | this.userAdminService.updateUsers(users, { emailVerified: true }) | 269 | this.userAdminService.updateUsers(users, { emailVerified: true }) |
225 | .subscribe({ | 270 | .subscribe({ |
226 | next: () => { | 271 | next: () => { |
227 | this.notifier.success($localize`${users.length} users email set as verified.`) | 272 | this.notifier.success( |
273 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} email set as verified.`)( | ||
274 | { count: users.length }, | ||
275 | $localize`${users.length} users email set as verified.` | ||
276 | ) | ||
277 | ) | ||
278 | |||
228 | this.reloadData() | 279 | this.reloadData() |
229 | }, | 280 | }, |
230 | 281 | ||