1 import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core'
2 import { AuthService, ConfirmService, Notifier, ServerService, UserService } from '@app/core'
3 import { Account, DropdownAction } from '@app/shared/shared-main'
4 import { BulkRemoveCommentsOfBody, ServerConfig, User, UserRight } from '@shared/models'
5 import { BlocklistService } from './blocklist.service'
6 import { BulkService } from './bulk.service'
7 import { UserBanModalComponent } from './user-ban-modal.component'
10 selector: 'my-user-moderation-dropdown',
11 templateUrl: './user-moderation-dropdown.component.html'
13 export class UserModerationDropdownComponent implements OnInit, OnChanges {
14 @ViewChild('userBanModal') userBanModal: UserBanModalComponent
17 @Input() account: Account
18 @Input() prependActions: DropdownAction<{ user: User, account: Account }>[]
20 @Input() buttonSize: 'normal' | 'small' = 'normal'
21 @Input() buttonStyled = true
22 @Input() placement = 'right-top right-bottom auto'
23 @Input() label: string
24 @Input() container: 'body' | undefined = undefined
26 @Output() userChanged = new EventEmitter()
27 @Output() userDeleted = new EventEmitter()
29 userActions: DropdownAction<{ user: User, account: Account }>[][] = []
31 private serverConfig: ServerConfig
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 bulkService: BulkService
43 get requiresEmailVerification () {
44 return this.serverConfig.signup.requiresEmailVerification
48 this.serverConfig = this.serverService.getTmpConfig()
49 this.serverService.getConfig()
50 .subscribe(config => this.serverConfig = config)
57 openBanUserModal (user: User) {
58 if (user.username === 'root') {
59 this.notifier.error($localize`You cannot ban root.`)
63 this.userBanModal.openModal(user)
67 this.userChanged.emit()
70 async unbanUser (user: User) {
71 const res = await this.confirmService.confirm($localize`Do you really want to unban ${user.username}?`, $localize`Unban`)
72 if (res === false) return
74 this.userService.unbanUsers(user)
77 this.notifier.success($localize`User ${user.username} unbanned.`)
78 this.userChanged.emit()
81 err => this.notifier.error(err.message)
85 async removeUser (user: User) {
86 if (user.username === 'root') {
87 this.notifier.error($localize`You cannot delete root.`)
91 const message = $localize`If you remove this user, you will not be able to create another with the same username!`
92 const res = await this.confirmService.confirm(message, $localize`Delete`)
93 if (res === false) return
95 this.userService.removeUser(user).subscribe(
97 this.notifier.success($localize`User ${user.username} deleted.`)
98 this.userDeleted.emit()
101 err => this.notifier.error(err.message)
105 setEmailAsVerified (user: User) {
106 this.userService.updateUser(user.id, { emailVerified: true }).subscribe(
108 this.notifier.success($localize`User ${user.username} email set as verified`)
109 this.userChanged.emit()
112 err => this.notifier.error(err.message)
116 blockAccountByUser (account: Account) {
117 this.blocklistService.blockAccountByUser(account)
120 this.notifier.success($localize`Account ${account.nameWithHost} muted.`)
122 this.account.mutedByUser = true
123 this.userChanged.emit()
126 err => this.notifier.error(err.message)
130 unblockAccountByUser (account: Account) {
131 this.blocklistService.unblockAccountByUser(account)
134 this.notifier.success($localize`Account ${account.nameWithHost} unmuted.`)
136 this.account.mutedByUser = false
137 this.userChanged.emit()
140 err => this.notifier.error(err.message)
144 blockServerByUser (host: string) {
145 this.blocklistService.blockServerByUser(host)
148 this.notifier.success($localize`Instance ${host} muted.`)
150 this.account.mutedServerByUser = true
151 this.userChanged.emit()
154 err => this.notifier.error(err.message)
158 unblockServerByUser (host: string) {
159 this.blocklistService.unblockServerByUser(host)
162 this.notifier.success($localize`Instance ${host} unmuted.`)
164 this.account.mutedServerByUser = false
165 this.userChanged.emit()
168 err => this.notifier.error(err.message)
172 blockAccountByInstance (account: Account) {
173 this.blocklistService.blockAccountByInstance(account)
176 this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`)
178 this.account.mutedByInstance = true
179 this.userChanged.emit()
182 err => this.notifier.error(err.message)
186 unblockAccountByInstance (account: Account) {
187 this.blocklistService.unblockAccountByInstance(account)
190 this.notifier.success($localize`Account ${account.nameWithHost} unmuted by the instance.`)
192 this.account.mutedByInstance = false
193 this.userChanged.emit()
196 err => this.notifier.error(err.message)
200 blockServerByInstance (host: string) {
201 this.blocklistService.blockServerByInstance(host)
204 this.notifier.success($localize`Instance ${host} muted by the instance.`)
206 this.account.mutedServerByInstance = true
207 this.userChanged.emit()
210 err => this.notifier.error(err.message)
214 unblockServerByInstance (host: string) {
215 this.blocklistService.unblockServerByInstance(host)
218 this.notifier.success($localize`Instance ${host} unmuted by the instance.`)
220 this.account.mutedServerByInstance = false
221 this.userChanged.emit()
224 err => this.notifier.error(err.message)
228 async bulkRemoveCommentsOf (body: BulkRemoveCommentsOfBody) {
229 const message = $localize`Are you sure you want to remove all the comments of this account?`
230 const res = await this.confirmService.confirm(message, $localize`Delete account comments`)
231 if (res === false) return
233 this.bulkService.removeCommentsOf(body)
236 this.notifier.success($localize`Will remove comments of this account (may take several minutes).`)
239 err => this.notifier.error(err.message)
243 getRouterUserEditLink (user: User) {
244 return [ '/admin', 'users', 'update', user.id ]
247 private buildActions () {
248 this.userActions = []
250 if (this.prependActions) {
256 if (this.authService.isLoggedIn()) {
257 const authUser = this.authService.getUser()
259 if (this.user && authUser.id === this.user.id) return
261 if (this.user && authUser.hasRight(UserRight.MANAGE_USERS) && authUser.canManage(this.user)) {
262 this.userActions.push([
264 label: $localize`Edit user`,
265 description: $localize`Change quota, role, and more.`,
266 linkBuilder: ({ user }) => this.getRouterUserEditLink(user)
269 label: $localize`Delete user`,
270 description: $localize`Videos will be deleted, comments will be tombstoned.`,
271 handler: ({ user }) => this.removeUser(user)
274 label: $localize`Ban`,
275 description: $localize`User won't be able to login anymore, but videos and comments will be kept as is.`,
276 handler: ({ user }) => this.openBanUserModal(user),
277 isDisplayed: ({ user }) => !user.blocked
280 label: $localize`Unban user`,
281 description: $localize`Allow the user to login and create videos/comments again`,
282 handler: ({ user }) => this.unbanUser(user),
283 isDisplayed: ({ user }) => user.blocked
286 label: $localize`Set Email as Verified`,
287 handler: ({ user }) => this.setEmailAsVerified(user),
288 isDisplayed: ({ user }) => this.requiresEmailVerification && !user.blocked && user.emailVerified === false
293 // Actions on accounts/servers
296 this.userActions.push([
298 label: $localize`Mute this account`,
299 description: $localize`Hide any content from that user from you.`,
300 isDisplayed: ({ account }) => account.mutedByUser === false,
301 handler: ({ account }) => this.blockAccountByUser(account)
304 label: $localize`Unmute this account`,
305 description: $localize`Show back content from that user for you.`,
306 isDisplayed: ({ account }) => account.mutedByUser === true,
307 handler: ({ account }) => this.unblockAccountByUser(account)
310 label: $localize`Mute the instance`,
311 description: $localize`Hide any content from that instance for you.`,
312 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
313 handler: ({ account }) => this.blockServerByUser(account.host)
316 label: $localize`Unmute the instance`,
317 description: $localize`Show back content from that instance for you.`,
318 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
319 handler: ({ account }) => this.unblockServerByUser(account.host)
322 label: $localize`Remove comments from your videos`,
323 description: $localize`Remove comments made by this account on your videos.`,
324 handler: ({ account }) => this.bulkRemoveCommentsOf({ accountName: account.nameWithHost, scope: 'my-videos' })
328 let instanceActions: DropdownAction<{ user: User, account: Account }>[] = []
330 // Instance actions on account blocklists
331 if (authUser.hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)) {
332 instanceActions = instanceActions.concat([
334 label: $localize`Mute this account by your instance`,
335 description: $localize`Hide any content from that user from you, your instance and its users.`,
336 isDisplayed: ({ account }) => account.mutedByInstance === false,
337 handler: ({ account }) => this.blockAccountByInstance(account)
340 label: $localize`Unmute this account by your instance`,
341 description: $localize`Show this user's content to the users of this instance again.`,
342 isDisplayed: ({ account }) => account.mutedByInstance === true,
343 handler: ({ account }) => this.unblockAccountByInstance(account)
348 // Instance actions on server blocklists
349 if (authUser.hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)) {
350 instanceActions = instanceActions.concat([
352 label: $localize`Mute the instance by your instance`,
353 description: $localize`Hide any content from that instance from you, your instance and its users.`,
354 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
355 handler: ({ account }) => this.blockServerByInstance(account.host)
358 label: $localize`Unmute the instance by your instance`,
359 description: $localize`Show back content from that instance for you, your instance and its users.`,
360 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
361 handler: ({ account }) => this.unblockServerByInstance(account.host)
366 if (authUser.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT)) {
367 instanceActions = instanceActions.concat([
369 label: $localize`Remove comments from your instance`,
370 description: $localize`Remove comments made by this account from your instance.`,
371 handler: ({ account }) => this.bulkRemoveCommentsOf({ accountName: account.nameWithHost, scope: 'instance' })
376 if (instanceActions.length !== 0) {
377 this.userActions.push(instanceActions)