Add checkbox focus shadows, and admin resolution descriptions
[oweals/peertube.git] / client / src / app / shared / moderation / user-moderation-dropdown.component.ts
1 import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core'
2 import { I18n } from '@ngx-translate/i18n-polyfill'
3 import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
4 import { UserBanModalComponent } from '@app/shared/moderation/user-ban-modal.component'
5 import { UserService } from '@app/shared/users'
6 import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core'
7 import { User, UserRight } from '../../../../../shared/models/users'
8 import { Account } from '@app/shared/account/account.model'
9 import { BlocklistService } from '@app/shared/blocklist'
10 import { ServerConfig } from '@shared/models'
11
12 @Component({
13   selector: 'my-user-moderation-dropdown',
14   templateUrl: './user-moderation-dropdown.component.html'
15 })
16 export class UserModerationDropdownComponent implements OnInit, OnChanges {
17   @ViewChild('userBanModal', { static: false }) userBanModal: UserBanModalComponent
18
19   @Input() user: User
20   @Input() account: Account
21
22   @Input() buttonSize: 'normal' | 'small' = 'normal'
23   @Input() placement = 'left'
24   @Input() label: string
25
26   @Output() userChanged = new EventEmitter()
27   @Output() userDeleted = new EventEmitter()
28
29   userActions: DropdownAction<{ user: User, account: Account }>[][] = []
30
31   private serverConfig: ServerConfig
32
33   constructor (
34     private authService: AuthService,
35     private notifier: Notifier,
36     private confirmService: ConfirmService,
37     private serverService: ServerService,
38     private userService: UserService,
39     private blocklistService: BlocklistService,
40     private i18n: I18n
41   ) { }
42
43   get requiresEmailVerification () {
44     return this.serverConfig.signup.requiresEmailVerification
45   }
46
47   ngOnInit (): void {
48     this.serverConfig = this.serverService.getTmpConfig()
49     this.serverService.getConfig()
50       .subscribe(config => this.serverConfig = config)
51   }
52
53   ngOnChanges () {
54     this.buildActions()
55   }
56
57   openBanUserModal (user: User) {
58     if (user.username === 'root') {
59       this.notifier.error(this.i18n('You cannot ban root.'))
60       return
61     }
62
63     this.userBanModal.openModal(user)
64   }
65
66   onUserBanned () {
67     this.userChanged.emit()
68   }
69
70   async unbanUser (user: User) {
71     const message = this.i18n('Do you really want to unban {{username}}?', { username: user.username })
72     const res = await this.confirmService.confirm(message, this.i18n('Unban'))
73     if (res === false) return
74
75     this.userService.unbanUsers(user)
76         .subscribe(
77           () => {
78             this.notifier.success(this.i18n('User {{username}} unbanned.', { username: user.username }))
79
80             this.userChanged.emit()
81           },
82
83           err => this.notifier.error(err.message)
84         )
85   }
86
87   async removeUser (user: User) {
88     if (user.username === 'root') {
89       this.notifier.error(this.i18n('You cannot delete root.'))
90       return
91     }
92
93     const message = this.i18n('If you remove this user, you will not be able to create another with the same username!')
94     const res = await this.confirmService.confirm(message, this.i18n('Delete'))
95     if (res === false) return
96
97     this.userService.removeUser(user).subscribe(
98       () => {
99         this.notifier.success(this.i18n('User {{username}} deleted.', { username: user.username }))
100         this.userDeleted.emit()
101       },
102
103       err => this.notifier.error(err.message)
104     )
105   }
106
107   setEmailAsVerified (user: User) {
108     this.userService.updateUser(user.id, { emailVerified: true }).subscribe(
109       () => {
110         this.notifier.success(this.i18n('User {{username}} email set as verified', { username: user.username }))
111
112         this.userChanged.emit()
113       },
114
115       err => this.notifier.error(err.message)
116     )
117   }
118
119   blockAccountByUser (account: Account) {
120     this.blocklistService.blockAccountByUser(account)
121         .subscribe(
122           () => {
123             this.notifier.success(this.i18n('Account {{nameWithHost}} muted.', { nameWithHost: account.nameWithHost }))
124
125             this.account.mutedByUser = true
126             this.userChanged.emit()
127           },
128
129           err => this.notifier.error(err.message)
130         )
131   }
132
133   unblockAccountByUser (account: Account) {
134     this.blocklistService.unblockAccountByUser(account)
135         .subscribe(
136           () => {
137             this.notifier.success(this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: account.nameWithHost }))
138
139             this.account.mutedByUser = false
140             this.userChanged.emit()
141           },
142
143           err => this.notifier.error(err.message)
144         )
145   }
146
147   blockServerByUser (host: string) {
148     this.blocklistService.blockServerByUser(host)
149         .subscribe(
150           () => {
151             this.notifier.success(this.i18n('Instance {{host}} muted.', { host }))
152
153             this.account.mutedServerByUser = true
154             this.userChanged.emit()
155           },
156
157           err => this.notifier.error(err.message)
158         )
159   }
160
161   unblockServerByUser (host: string) {
162     this.blocklistService.unblockServerByUser(host)
163         .subscribe(
164           () => {
165             this.notifier.success(this.i18n('Instance {{host}} unmuted.', { host }))
166
167             this.account.mutedServerByUser = false
168             this.userChanged.emit()
169           },
170
171           err => this.notifier.error(err.message)
172         )
173   }
174
175   blockAccountByInstance (account: Account) {
176     this.blocklistService.blockAccountByInstance(account)
177         .subscribe(
178           () => {
179             this.notifier.success(this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost }))
180
181             this.account.mutedByInstance = true
182             this.userChanged.emit()
183           },
184
185           err => this.notifier.error(err.message)
186         )
187   }
188
189   unblockAccountByInstance (account: Account) {
190     this.blocklistService.unblockAccountByInstance(account)
191         .subscribe(
192           () => {
193             this.notifier.success(this.i18n('Account {{nameWithHost}} unmuted by the instance.', { nameWithHost: account.nameWithHost }))
194
195             this.account.mutedByInstance = false
196             this.userChanged.emit()
197           },
198
199           err => this.notifier.error(err.message)
200         )
201   }
202
203   blockServerByInstance (host: string) {
204     this.blocklistService.blockServerByInstance(host)
205         .subscribe(
206           () => {
207             this.notifier.success(this.i18n('Instance {{host}} muted by the instance.', { host }))
208
209             this.account.mutedServerByInstance = true
210             this.userChanged.emit()
211           },
212
213           err => this.notifier.error(err.message)
214         )
215   }
216
217   unblockServerByInstance (host: string) {
218     this.blocklistService.unblockServerByInstance(host)
219         .subscribe(
220           () => {
221             this.notifier.success(this.i18n('Instance {{host}} unmuted by the instance.', { host }))
222
223             this.account.mutedServerByInstance = false
224             this.userChanged.emit()
225           },
226
227           err => this.notifier.error(err.message)
228         )
229   }
230
231   getRouterUserEditLink (user: User) {
232     return [ '/admin', 'users', 'update', user.id ]
233   }
234
235   private buildActions () {
236     this.userActions = []
237
238     if (this.authService.isLoggedIn()) {
239       const authUser = this.authService.getUser()
240
241       if (this.user && authUser.id === this.user.id) return
242
243       if (this.user && authUser.hasRight(UserRight.MANAGE_USERS) && authUser.canManage(this.user)) {
244         this.userActions.push([
245           {
246             label: this.i18n('Edit user'),
247             linkBuilder: ({ user }) => this.getRouterUserEditLink(user)
248           },
249           {
250             label: this.i18n('Delete user'),
251             handler: ({ user }) => this.removeUser(user)
252           },
253           {
254             label: this.i18n('Ban user'),
255             handler: ({ user }) => this.openBanUserModal(user),
256             isDisplayed: ({ user }) => !user.blocked
257           },
258           {
259             label: this.i18n('Unban user'),
260             handler: ({ user }) => this.unbanUser(user),
261             isDisplayed: ({ user }) => user.blocked
262           },
263           {
264             label: this.i18n('Set Email as Verified'),
265             handler: ({ user }) => this.setEmailAsVerified(user),
266             isDisplayed: ({ user }) => this.requiresEmailVerification && !user.blocked && user.emailVerified === false
267           }
268         ])
269       }
270
271       // Actions on accounts/servers
272       if (this.account) {
273         // User actions
274         this.userActions.push([
275           {
276             label: this.i18n('Mute this account'),
277             isDisplayed: ({ account }) => account.mutedByUser === false,
278             handler: ({ account }) => this.blockAccountByUser(account)
279           },
280           {
281             label: this.i18n('Unmute this account'),
282             isDisplayed: ({ account }) => account.mutedByUser === true,
283             handler: ({ account }) => this.unblockAccountByUser(account)
284           },
285           {
286             label: this.i18n('Mute the instance'),
287             isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
288             handler: ({ account }) => this.blockServerByUser(account.host)
289           },
290           {
291             label: this.i18n('Unmute the instance'),
292             isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
293             handler: ({ account }) => this.unblockServerByUser(account.host)
294           }
295         ])
296
297         let instanceActions: DropdownAction<{ user: User, account: Account }>[] = []
298
299         // Instance actions
300         if (authUser.hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)) {
301           instanceActions = instanceActions.concat([
302             {
303               label: this.i18n('Mute this account by your instance'),
304               isDisplayed: ({ account }) => account.mutedByInstance === false,
305               handler: ({ account }) => this.blockAccountByInstance(account)
306             },
307             {
308               label: this.i18n('Unmute this account by your instance'),
309               isDisplayed: ({ account }) => account.mutedByInstance === true,
310               handler: ({ account }) => this.unblockAccountByInstance(account)
311             }
312           ])
313         }
314
315         // Instance actions
316         if (authUser.hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)) {
317           instanceActions = instanceActions.concat([
318             {
319               label: this.i18n('Mute the instance by your instance'),
320               isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
321               handler: ({ account }) => this.blockServerByInstance(account.host)
322             },
323             {
324               label: this.i18n('Unmute the instance by your instance'),
325               isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
326               handler: ({ account }) => this.unblockServerByInstance(account.host)
327             }
328           ])
329         }
330
331         if (instanceActions.length !== 0) {
332           this.userActions.push(instanceActions)
333         }
334       }
335     }
336   }
337 }