aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+admin/overview/users/user-list/user-list.component.ts
diff options
context:
space:
mode:
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.ts92
1 files changed, 72 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..91f42546b 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 @@
1import { SortMeta } from 'primeng/api' 1import { SortMeta } from 'primeng/api'
2import { Component, OnInit, ViewChild } from '@angular/core' 2import { Component, OnInit, ViewChild } from '@angular/core'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' 4import { AuthService, ConfirmService, LocalStorageService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
5import { getAPIHost } from '@app/helpers' 5import { prepareIcu, getAPIHost } from '@app/helpers'
6import { AdvancedInputFilter } from '@app/shared/shared-forms' 6import { AdvancedInputFilter } from '@app/shared/shared-forms'
7import { Actor, DropdownAction } from '@app/shared/shared-main' 7import { Actor, DropdownAction } from '@app/shared/shared-main'
8import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' 8import { 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})
24export class UserListComponent extends RestTable implements OnInit { 24export 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 () {
@@ -164,6 +190,7 @@ export class UserListComponent extends RestTable implements OnInit {
164 } 190 }
165 191
166 getUserVideoQuotaDailyPercentage (user: UserForList) { 192 getUserVideoQuotaDailyPercentage (user: UserForList) {
193 console.log(user.rawVideoQuotaUsedDaily * 100 / user.rawVideoQuotaDaily)
167 return user.rawVideoQuotaUsedDaily * 100 / user.rawVideoQuotaDaily 194 return user.rawVideoQuotaUsedDaily * 100 / user.rawVideoQuotaDaily
168 } 195 }
169 196
@@ -183,13 +210,25 @@ export class UserListComponent extends RestTable implements OnInit {
183 } 210 }
184 211
185 async unbanUsers (users: User[]) { 212 async unbanUsers (users: User[]) {
186 const res = await this.confirmService.confirm($localize`Do you really want to unban ${users.length} users?`, $localize`Unban`) 213 const res = await this.confirmService.confirm(
214 prepareIcu($localize`Do you really want to unban {count, plural, =1 {1 user} other {{count} users}}?`)(
215 { count: users.length },
216 $localize`Do you really want to unban ${users.length} users?`
217 ),
218 $localize`Unban`
219 )
220
187 if (res === false) return 221 if (res === false) return
188 222
189 this.userAdminService.unbanUsers(users) 223 this.userAdminService.unbanUsers(users)
190 .subscribe({ 224 .subscribe({
191 next: () => { 225 next: () => {
192 this.notifier.success($localize`${users.length} users unbanned.`) 226 this.notifier.success(
227 prepareIcu($localize`{count, plural, =1 {1 user unbanned.} other {{count} users unbanned.}}`)(
228 { count: users.length },
229 $localize`${users.length} users unbanned.`
230 )
231 )
193 this.reloadData() 232 this.reloadData()
194 }, 233 },
195 234
@@ -198,21 +237,28 @@ export class UserListComponent extends RestTable implements OnInit {
198 } 237 }
199 238
200 async removeUsers (users: User[]) { 239 async removeUsers (users: User[]) {
201 for (const user of users) { 240 if (users.some(u => u.username === 'root')) {
202 if (user.username === 'root') { 241 this.notifier.error($localize`You cannot delete root.`)
203 this.notifier.error($localize`You cannot delete root.`) 242 return
204 return
205 }
206 } 243 }
207 244
208 const message = $localize`If you remove these users, you will not be able to create others with the same username!` 245 const message = $localize`<p>You can't create users or channels with a username that already used by a deleted user/channel.</p>` +
246 $localize`It means the following usernames will be permanently deleted and cannot be recovered:` +
247 '<ul>' + users.map(u => '<li>' + u.username + '</li>').join('') + '</ul>'
248
209 const res = await this.confirmService.confirm(message, $localize`Delete`) 249 const res = await this.confirmService.confirm(message, $localize`Delete`)
210 if (res === false) return 250 if (res === false) return
211 251
212 this.userAdminService.removeUser(users) 252 this.userAdminService.removeUser(users)
213 .subscribe({ 253 .subscribe({
214 next: () => { 254 next: () => {
215 this.notifier.success($localize`${users.length} users deleted.`) 255 this.notifier.success(
256 prepareIcu($localize`{count, plural, =1 {1 user deleted.} other {{count} users deleted.}}`)(
257 { count: users.length },
258 $localize`${users.length} users deleted.`
259 )
260 )
261
216 this.reloadData() 262 this.reloadData()
217 }, 263 },
218 264
@@ -224,7 +270,13 @@ export class UserListComponent extends RestTable implements OnInit {
224 this.userAdminService.updateUsers(users, { emailVerified: true }) 270 this.userAdminService.updateUsers(users, { emailVerified: true })
225 .subscribe({ 271 .subscribe({
226 next: () => { 272 next: () => {
227 this.notifier.success($localize`${users.length} users email set as verified.`) 273 this.notifier.success(
274 prepareIcu($localize`{count, plural, =1 {1 user email set as verified.} other {{count} user emails set as verified.}}`)(
275 { count: users.length },
276 $localize`${users.length} users email set as verified.`
277 )
278 )
279
228 this.reloadData() 280 this.reloadData()
229 }, 281 },
230 282