1.0.0 #253
| @@ -1,5 +1,5 @@ | ||||
| import { Data } from "./data.model"; | ||||
| import { Server, ServerFilter } from "./server.model"; | ||||
| import {Data} from "./data.model"; | ||||
| import {Server, ServerFilter} from "./server.model"; | ||||
|  | ||||
| export interface Level extends Data { | ||||
|   id?: number; | ||||
| @@ -12,6 +12,6 @@ export interface Level extends Data { | ||||
|  | ||||
| export interface LevelFilter { | ||||
|   id?: number; | ||||
|   name?: String; | ||||
|   name?: string; | ||||
|   server?: ServerFilter; | ||||
| } | ||||
|   | ||||
| @@ -79,4 +79,46 @@ export class Mutations { | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static createLevel = ` | ||||
|     mutation createLevel($name: String, $color: String, $minXp: Int, $permissions: String, $serverId: ID) { | ||||
|       level { | ||||
|         createLevel(input: { name: $name, color: $color, minXp: $minXp, permissions: $permissions, serverId: $serverId}) { | ||||
|           id | ||||
|           name | ||||
|           color | ||||
|           minXp | ||||
|           permissions | ||||
|           server { | ||||
|             id | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static updateLevel = ` | ||||
|     mutation updateLevel($id: ID, $name: String, $color: String, $minXp: Int, $permissions: String) { | ||||
|       level { | ||||
|         updateLevel(input: { id: $id, name: $name, color: $color, minXp: $minXp, permissions: $permissions }) { | ||||
|           id | ||||
|           name | ||||
|           color | ||||
|           minXp | ||||
|           permissions | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static deleteLevel = ` | ||||
|     mutation deleteLevel($id: ID) { | ||||
|       level { | ||||
|         deleteLevel(id: $id) { | ||||
|           id | ||||
|           name | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { User } from "../data/user.model"; | ||||
| import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; | ||||
| import { Level } from "../data/level.model"; | ||||
|  | ||||
| export interface GraphQLResult { | ||||
|   data: any; | ||||
| @@ -31,3 +32,11 @@ export interface AutoRoleRuleMutationResult { | ||||
|     deleteAutoRoleRule?: AutoRoleRule | ||||
|   }; | ||||
| } | ||||
|  | ||||
| export interface LevelMutationResult { | ||||
|   level: { | ||||
|     createLevel?: Level | ||||
|     updateLevel?: Level | ||||
|     deleteLevel?: Level | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -18,10 +18,10 @@ | ||||
|  | ||||
|           <div class="table-caption-btn-wrapper btn-wrapper"> | ||||
|             <button pButton label="{{'admin.auth_users.add' | translate}}" class="icon-btn btn" | ||||
|                     icon="pi pi-user-plus" [disabled]="isEditingNew"> | ||||
|                     icon="pi pi-user-plus" (click)="addLevel(dt)" [disabled]="isEditingNew"> | ||||
|             </button> | ||||
|             <button pButton label="{{'view.server.levels.reset_filters' | translate}}" icon="pi pi-undo" | ||||
|                     class="icon-btn btn"> | ||||
|                     class="icon-btn btn" (click)="resetFilters()"> | ||||
|             </button> | ||||
|           </div> | ||||
|         </div> | ||||
| @@ -121,7 +121,7 @@ | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{level.name}} | ||||
|                 <input class="table-edit-input" pInputText type="text" [(ngModel)]="level.name"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{level.name}} | ||||
| @@ -132,7 +132,7 @@ | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{level.color}} | ||||
|                 <input class="table-edit-input" pInputText type="text" [(ngModel)]="level.color"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{level.color}} | ||||
| @@ -143,7 +143,7 @@ | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{level.minXp}} | ||||
|                 <input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="level.minXp"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{level.minXp}} | ||||
| @@ -154,7 +154,7 @@ | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{level.permissions}} | ||||
|                 <input class="table-edit-input" pInputText min="0" type="text" [(ngModel)]="level.permissions"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{level.permissions}} | ||||
| @@ -182,18 +182,17 @@ | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <div class="btn-wrapper"> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" | ||||
|               ></button> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-user" | ||||
|                       [routerLink]="[level.id, 'rules']"></button> | ||||
|                       (click)="onRowEditInit(dt, level, ri)"></button> | ||||
|               <button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash" | ||||
|                       (click)="deleteLevel(level)"></button> | ||||
|  | ||||
|               <button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn" | ||||
|                       icon="pi pi-check-circle"></button> | ||||
|                       icon="pi pi-check-circle" (click)="onRowEditSave(dt, level, ri)"></button> | ||||
|               <button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn" | ||||
|                       icon="pi pi-times-circle"></button> | ||||
|                       icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button> | ||||
|             </div> | ||||
|           </td> | ||||
|         </tr> | ||||
| @@ -202,7 +201,7 @@ | ||||
|       <ng-template pTemplate="emptymessage"> | ||||
|         <tr></tr> | ||||
|         <tr> | ||||
|           <td colspan="10">{{'view.server.auto_roles.no_entries_found' | translate}}</td> | ||||
|           <td colspan="10">{{'view.server.levels.no_entries_found' | translate}}</td> | ||||
|         </tr> | ||||
|         <tr></tr> | ||||
|       </ng-template> | ||||
|   | ||||
| @@ -13,8 +13,13 @@ import {Sort, SortDirection} from "../../../../../../models/graphql/filter/sort. | ||||
| import {Level, LevelFilter} from "../../../../../../models/data/level.model"; | ||||
| import {LevelListQuery} from "../../../../../../models/graphql/query.model"; | ||||
| import {Queries} from "../../../../../../models/graphql/queries.model"; | ||||
| import {debounceTime} from "rxjs/operators"; | ||||
| import {catchError, debounceTime} from "rxjs/operators"; | ||||
| import {LazyLoadEvent} from "primeng/api"; | ||||
| import {Table} from "primeng/table"; | ||||
| import {User} from "../../../../../../models/data/user.model"; | ||||
| import {LevelMutationResult, UpdateUserMutationResult} from "../../../../../../models/graphql/result.model"; | ||||
| import {Mutations} from "../../../../../../models/graphql/mutations.model"; | ||||
| import {throwError} from "rxjs"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-levels', | ||||
| @@ -23,12 +28,12 @@ import {LazyLoadEvent} from "primeng/api"; | ||||
| }) | ||||
| export class LevelsComponent { | ||||
|  | ||||
|   levels!: Level[]; | ||||
|   loading = true; | ||||
|   public levels!: Level[]; | ||||
|   public loading = true; | ||||
|  | ||||
|   isEditingNew: boolean = false; | ||||
|   public isEditingNew: boolean = false; | ||||
|  | ||||
|   filterForm!: FormGroup<{ | ||||
|   public filterForm!: FormGroup<{ | ||||
|     id: FormControl<number | null>, | ||||
|     name: FormControl<string | null>, | ||||
|     color: FormControl<string | null>, | ||||
| @@ -36,17 +41,19 @@ export class LevelsComponent { | ||||
|     permissions: FormControl<number | null>, | ||||
|   }>; | ||||
|  | ||||
|   filter: LevelFilter = {}; | ||||
|   page: Page = { | ||||
|   public filter: LevelFilter = {}; | ||||
|   public page: Page = { | ||||
|     pageSize: undefined, | ||||
|     pageIndex: undefined | ||||
|   }; | ||||
|   sort: Sort = { | ||||
|   public sort: Sort = { | ||||
|     sortColumn: undefined, | ||||
|     sortDirection: undefined | ||||
|   }; | ||||
|  | ||||
|   totalRecords!: number; | ||||
|   public totalRecords!: number; | ||||
|  | ||||
|   public clonedLevels: { [s: string]: Level; } = {}; | ||||
|  | ||||
|   public constructor( | ||||
|     private authService: AuthService, | ||||
| @@ -67,7 +74,7 @@ export class LevelsComponent { | ||||
|     this.loadNextPage(); | ||||
|   } | ||||
|  | ||||
|   public loadNextPage() { | ||||
|   public loadNextPage(): void { | ||||
|     this.loading = true; | ||||
|     this.data.query<LevelListQuery>(Queries.levelQuery, { | ||||
|         filter: this.filter, page: this.page, sort: this.sort | ||||
| @@ -80,7 +87,7 @@ export class LevelsComponent { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   public setFilterForm() { | ||||
|   public setFilterForm(): void { | ||||
|     this.filterForm = this.fb.group({ | ||||
|       id: new FormControl<number | null>(null), | ||||
|       name: new FormControl<string | null>(null), | ||||
| @@ -114,7 +121,13 @@ export class LevelsComponent { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   public nextPage(event: LazyLoadEvent) { | ||||
|   public newLevelTemplate: Level = { | ||||
|     id: 0, | ||||
|     createdAt: "", | ||||
|     modifiedAt: "" | ||||
|   }; | ||||
|  | ||||
|   public nextPage(event: LazyLoadEvent): void { | ||||
|     this.page.pageSize = event.rows ?? 0; | ||||
|     if (event.first != null && event.rows != null) | ||||
|       this.page.pageIndex = event.first / event.rows; | ||||
| @@ -124,4 +137,121 @@ export class LevelsComponent { | ||||
|     this.loadNextPage(); | ||||
|   } | ||||
|  | ||||
|   public resetFilters(): void { | ||||
|     this.filterForm.reset(); | ||||
|   } | ||||
|  | ||||
|   public onRowEditInit(table: Table, user: User, index: number): void { | ||||
|     this.clonedLevels[index] = {...user}; | ||||
|   } | ||||
|  | ||||
|   public onRowEditSave(table: Table, newLevel: Level, index: number): void { | ||||
|     // const oldUser = this.clonedUsers[index]; | ||||
|     // delete this.clonedUsers[index]; | ||||
|  | ||||
|     // if (JSON.stringify(oldUser) === JSON.stringify(newUser) && !this.isEditingNew) { | ||||
|     //   console.log(1, oldUser, newUser, JSON.stringify(oldUser) === JSON.stringify(newUser), !this.isEditingNew); | ||||
|     //   return; | ||||
|     // } | ||||
|  | ||||
|     if (this.isEditingNew && JSON.stringify(newLevel) === JSON.stringify(this.newLevelTemplate)) { | ||||
|       this.isEditingNew = false; | ||||
|       this.levels.splice(index, 1); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!newLevel.id && !this.isEditingNew || !newLevel.minXp && !newLevel?.name && !newLevel?.permissions) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (this.isEditingNew) { | ||||
|       this.spinner.showSpinner(); | ||||
|       this.data.mutation<LevelMutationResult>(Mutations.createLevel, { | ||||
|           name: newLevel.name, | ||||
|           color: newLevel.color, | ||||
|           minXp: newLevel.minXp, | ||||
|           permissions: newLevel.permissions, | ||||
|           serverId: this.sidebar.server$.value?.id | ||||
|         } | ||||
|       ).pipe(catchError(err => { | ||||
|         this.spinner.hideSpinner(); | ||||
|         this.toastService.error(this.translate.instant("view.server.levels.message.level_create_failed"), this.translate.instant("view.server.levels.message.level_create_failed_d")); | ||||
|         return throwError(err); | ||||
|       })).subscribe(result => { | ||||
|         this.isEditingNew = false; | ||||
|         this.spinner.hideSpinner(); | ||||
|         this.toastService.success(this.translate.instant("view.server.levels.message.level_create"), this.translate.instant("view.server.levels.message.level_create_d", {name: result.level.createLevel?.name})); | ||||
|         this.loadNextPage(); | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.spinner.showSpinner(); | ||||
|     this.data.mutation<UpdateUserMutationResult>(Mutations.updateLevel, { | ||||
|         id: newLevel.id, | ||||
|         name: newLevel.name, | ||||
|         color: newLevel.color, | ||||
|         minXp: newLevel.minXp, | ||||
|         permissions: newLevel.permissions, | ||||
|       } | ||||
|     ).pipe(catchError(err => { | ||||
|       this.spinner.hideSpinner(); | ||||
|       this.toastService.error(this.translate.instant("view.server.levels.message.level_update_failed"), this.translate.instant("view.server.levels.message.level_update_failed_d", {name: newLevel.name})); | ||||
|       return throwError(err); | ||||
|     })).subscribe(_ => { | ||||
|       this.spinner.hideSpinner(); | ||||
|       this.toastService.success(this.translate.instant("view.server.levels.message.level_update"), this.translate.instant("view.server.levels.message.level_update_d", {name: newLevel.name})); | ||||
|       this.loadNextPage(); | ||||
|     }); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   public onRowEditCancel(index: number): void { | ||||
|     if (this.isEditingNew) { | ||||
|       this.levels.splice(index, 1); | ||||
|       delete this.clonedLevels[index]; | ||||
|       this.isEditingNew = false; | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.levels[index] = this.clonedLevels[index]; | ||||
|     delete this.clonedLevels[index]; | ||||
|   } | ||||
|  | ||||
|   public deleteLevel(level: Level): void { | ||||
|     this.confirmDialog.confirmDialog( | ||||
|       this.translate.instant("view.server.levels.message.level_delete"), this.translate.instant("view.server.levels.message.level_delete_q", {name: level.name}), | ||||
|       () => { | ||||
|         this.spinner.showSpinner(); | ||||
|         this.data.mutation<LevelMutationResult>(Mutations.deleteLevel, { | ||||
|             id: level.id | ||||
|           } | ||||
|         ).pipe(catchError(err => { | ||||
|           this.spinner.hideSpinner(); | ||||
|           this.toastService.error(this.translate.instant("view.server.levels.message.level_delete_failed"), this.translate.instant("view.server.levels.message.level_delete_failedd", {name: level.name})); | ||||
|           return throwError(err); | ||||
|         })).subscribe(l => { | ||||
|           this.spinner.hideSpinner(); | ||||
|           this.toastService.success(this.translate.instant("view.server.levels.message.level_deleted"), this.translate.instant("view.server.levels.message.level_deleted_d", {name: level.name})); | ||||
|           this.loadNextPage(); | ||||
|         }); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   public addLevel(table: Table): void { | ||||
|     const newLevel = JSON.parse(JSON.stringify(this.newLevelTemplate)); | ||||
|     newLevel.id = Math.max.apply(Math, this.levels.map(l => { | ||||
|       return l.id ?? 0; | ||||
|     })) + 1; | ||||
|  | ||||
|     this.levels.push(newLevel); | ||||
|  | ||||
|     table.initRowEdit(newLevel); | ||||
|  | ||||
|     const index = this.levels.findIndex(l => l.id == newLevel.id); | ||||
|     this.onRowEditInit(table, newLevel, index); | ||||
|  | ||||
|     this.isEditingNew = true; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -97,29 +97,34 @@ | ||||
|         <tr> | ||||
|           <th class="table-header-small"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="id" placeholder="{{'view.server.members.headers.id' | translate}}"> | ||||
|               <input type="text" pInputText formControlName="id" | ||||
|                      placeholder="{{'view.server.members.headers.id' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th class="table-header-medium"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="discordId" placeholder="{{'view.server.members.headers.discord_id' | translate}}"> | ||||
|               <input type="text" pInputText formControlName="discordId" | ||||
|                      placeholder="{{'view.server.members.headers.discord_id' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="name" placeholder="{{'view.server.members.headers.name' | translate}}"> | ||||
|               <input type="text" pInputText formControlName="name" | ||||
|                      placeholder="{{'view.server.members.headers.name' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th></th> | ||||
|           <th></th> | ||||
|           <th class="table-header-small-dropdown"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <p-dropdown formControlName="leftServer" [options]="leftServerOptions" placeholder="{{'view.server.members.headers.left_server' | translate}}"></p-dropdown> | ||||
|               <p-dropdown formControlName="leftServer" [options]="leftServerOptions" | ||||
|                           placeholder="{{'view.server.members.headers.left_server' | translate}}"></p-dropdown> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th class="table-header-small-dropdown"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <p-dropdown formControlName="level" [options]="levels" placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown> | ||||
|               <p-dropdown formControlName="level" [options]="levels" | ||||
|                           placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th></th> | ||||
| @@ -194,7 +199,8 @@ | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <p-dropdown [options]="levels" [(ngModel)]="member.level" placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown> | ||||
|                 <p-dropdown [options]="levels" [(ngModel)]="member.level" | ||||
|                             placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{member.level.name}} | ||||
| @@ -225,12 +231,13 @@ | ||||
|             <div class="btn-wrapper"> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" | ||||
|                       (click)="onRowEditInit(dt, member, ri)"></button> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-user" [routerLink]="member.id"></button> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-user" | ||||
|                       [routerLink]="member.id"></button> | ||||
|  | ||||
|               <button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn" | ||||
|                       icon="pi pi-check-circle" (click)="onRowEditSave(dt, member, ri)"></button> | ||||
|               <button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn" | ||||
|                       icon="pi pi-times-circle" (click)="onRowEditCancel(member, ri)"></button> | ||||
|                       icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"></button> | ||||
|             </div> | ||||
|           </td> | ||||
|         </tr> | ||||
|   | ||||
| @@ -88,6 +88,7 @@ export class MembersComponent implements OnInit { | ||||
|     private fb: FormBuilder, | ||||
|     private translate: TranslateService, | ||||
|     private data: DataService, | ||||
|     private sidebar: SidebarService, | ||||
|     private route: ActivatedRoute | ||||
|   ) { | ||||
|   } | ||||
| @@ -234,7 +235,7 @@ export class MembersComponent implements OnInit { | ||||
|  | ||||
|   } | ||||
|  | ||||
|   onRowEditCancel(user: User, index: number) { | ||||
|   onRowEditCancel(index: number) { | ||||
|     if (this.isEditingNew) { | ||||
|       this.members.splice(index, 1); | ||||
|       delete this.clonedUsers[index]; | ||||
|   | ||||
| @@ -221,7 +221,7 @@ | ||||
|         "message": { | ||||
|           "user_changed": "Benutzer geändert", | ||||
|           "user_changed_d": "Benutzer {{name}} erfolgreich geändert", | ||||
|           "user_change_failed": "Benutzer änderung fehlgeschlagen", | ||||
|           "user_change_failed": "Benutzer Änderung fehlgeschlagen", | ||||
|           "user_change_failed_d": "Benutzer {{name}} konnte nicht geändert werden!" | ||||
|         } | ||||
|       }, | ||||
| @@ -298,10 +298,20 @@ | ||||
|         }, | ||||
|         "no_entries_found": "Keine Einträge gefunden", | ||||
|         "message": { | ||||
|           "level_changed": "Level geändert", | ||||
|           "level_changed_d": "Level {{name}} erfolgreich geändert", | ||||
|           "level_change_failed": "Level Änderung fehlgeschlagen", | ||||
|           "level_change_failed_d": "Level {{name}} konnte nicht geändert werden!" | ||||
|           "level_create": "Level erstellt", | ||||
|           "level_create_d": "Level {{name}} erfolgreich erstellt", | ||||
|           "level_create_failed": "Level Erstellung fehlgeschlagen", | ||||
|           "level_create_failed_d": "Die Erstellung des Levels ist fehlgeschlagen!", | ||||
|           "level_update": "Level bearbeitet", | ||||
|           "level_update_d": "Level {{name}} erfolgreich bearbeitet", | ||||
|           "level_update_failed": "Level Bearbeitung fehlgeschlagen", | ||||
|           "level_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!", | ||||
|           "level_delete": "Level löschen", | ||||
|           "level_delete_q": "Sind Sie sich sicher, dass Sie das Level {{name}} löschen möchten?", | ||||
|           "level_deleted": "Level gelöscht", | ||||
|           "level_deleted_d": "Level {{name}} erfolgreich gelöscht", | ||||
|           "level_delete_failed": "Level Löschung fehlgeschlagen", | ||||
|           "level_delete_failed_d": "Die Löschung des Levels {{name}} ist fehlgeschlagen!" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user