Added user service
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<dafa-skip-to-content mainContentId="dafa-main-content"></dafa-skip-to-content>
|
<dafa-skip-to-content mainContentId="dafa-main-content"></dafa-skip-to-content>
|
||||||
|
|
||||||
<header class="dafa__header">
|
<header class="dafa__header">
|
||||||
<dafa-navigation [user]="user"></dafa-navigation>
|
<dafa-navigation [currentUser]="currentUser$ | async"></dafa-navigation>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<dafa-sidebar class="dafa__sidebar"></dafa-sidebar>
|
<dafa-sidebar class="dafa__sidebar"></dafa-sidebar>
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-br
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { NavigationEnd, Router } from '@angular/router';
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
import { User } from '@dafa-models/user.model';
|
import { User } from '@dafa-models/user.model';
|
||||||
|
import { UserService } from '@dafa-services/api/user.service';
|
||||||
import { mapPathsToBreadcrumbs } from '@dafa-utils/map-paths-to-breadcrumbs.util';
|
import { mapPathsToBreadcrumbs } from '@dafa-utils/map-paths-to-breadcrumbs.util';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { filter } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
import { UnsubscribeDirective } from './directives/unsubscribe.directive';
|
import { UnsubscribeDirective } from './directives/unsubscribe.directive';
|
||||||
|
|
||||||
@@ -14,23 +15,18 @@ import { UnsubscribeDirective } from './directives/unsubscribe.directive';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AppComponent extends UnsubscribeDirective {
|
export class AppComponent extends UnsubscribeDirective {
|
||||||
user: User = {
|
|
||||||
id: 'fake-user',
|
|
||||||
name: 'Fake user',
|
|
||||||
};
|
|
||||||
|
|
||||||
private startBreadcrumb: NavigationBreadcrumbsItem = {
|
private startBreadcrumb: NavigationBreadcrumbsItem = {
|
||||||
text: 'Start',
|
text: 'Start',
|
||||||
routerLink: '/',
|
routerLink: '/',
|
||||||
};
|
};
|
||||||
|
|
||||||
private _breadcrumbsItems$ = new BehaviorSubject<NavigationBreadcrumbsItem[]>([this.startBreadcrumb]);
|
private _breadcrumbsItems$ = new BehaviorSubject<NavigationBreadcrumbsItem[]>([this.startBreadcrumb]);
|
||||||
|
public currentUser$: Observable<User> = this.userService.currentUser$;
|
||||||
|
|
||||||
get breadcrumbsItems(): NavigationBreadcrumbsItem[] {
|
get breadcrumbsItems(): NavigationBreadcrumbsItem[] {
|
||||||
return this._breadcrumbsItems$.getValue();
|
return this._breadcrumbsItems$.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private router: Router) {
|
constructor(private router: Router, private userService: UserService) {
|
||||||
super();
|
super();
|
||||||
super.unsubscribeOnDestroy(
|
super.unsubscribeOnDestroy(
|
||||||
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
|
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
<span class="navigation__text">Startsida</span>
|
<span class="navigation__text">Startsida</span>
|
||||||
</a>
|
</a>
|
||||||
</li> -->
|
</li> -->
|
||||||
<li class="navigation__item" *ngIf="user">
|
<li class="navigation__item" *ngIf="currentUser">
|
||||||
<div class="navigation__no-link">
|
<div class="navigation__no-link">
|
||||||
<dafa-icon [icon]="iconType.USER" size="l"></dafa-icon>
|
<dafa-icon [icon]="iconType.USER" size="l"></dafa-icon>
|
||||||
<span class="navigation__text">{{ user.name }}</span>
|
<span class="navigation__text">{{ currentUser.fullName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ import { User } from '@dafa-models/user.model';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class NavigationComponent {
|
export class NavigationComponent {
|
||||||
@Input() user: User;
|
@Input() currentUser: User;
|
||||||
iconType = IconType;
|
iconType = IconType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export interface EmployeeReponse {
|
export interface EmployeeResponse {
|
||||||
pxObjClass: string;
|
pxObjClass: string;
|
||||||
pyAccessGroup: string;
|
pyAccessGroup: string;
|
||||||
pyLabel: string;
|
pyLabel: string;
|
||||||
22
apps/dafa-web/src/app/data/models/api/user-response.model.ts
Normal file
22
apps/dafa-web/src/app/data/models/api/user-response.model.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
export interface UserResponse {
|
||||||
|
pxInsName: string;
|
||||||
|
pxLimitedAccess: string;
|
||||||
|
pxObjClass: string;
|
||||||
|
pyAccessGroup: string;
|
||||||
|
pyFirstName: string;
|
||||||
|
pyLastName: string;
|
||||||
|
pyLastSignon: string;
|
||||||
|
pyOrganization: string;
|
||||||
|
pyOrgDivision: string;
|
||||||
|
pyTelephone: string;
|
||||||
|
pyUserIdentifier: string;
|
||||||
|
pyUserName: string;
|
||||||
|
pyAccessGroupsAdditional: string[];
|
||||||
|
pyAddresses: {
|
||||||
|
Email: {
|
||||||
|
pxObjClass: string;
|
||||||
|
pxSubscript: string;
|
||||||
|
pyEmailAddress: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Agency } from '@dafa-models/agency.model';
|
import { Agency } from '@dafa-models/agency.model';
|
||||||
|
import { EmployeeResponse } from './api/employee-response.model';
|
||||||
import { Participant } from './participant.model';
|
import { Participant } from './participant.model';
|
||||||
import { EmployeeReponse } from './pega/employee-reponse.model';
|
|
||||||
|
|
||||||
export interface Employee {
|
export interface User {
|
||||||
id: string;
|
id: string;
|
||||||
employeeId: string;
|
employeeId: string;
|
||||||
firstName: string;
|
firstName: string;
|
||||||
@@ -13,7 +13,7 @@ export interface Employee {
|
|||||||
fullName?: string;
|
fullName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmployeeDetail extends Employee {
|
export interface EmployeeDetail extends User {
|
||||||
languages: string[];
|
languages: string[];
|
||||||
outOfOffice: {
|
outOfOffice: {
|
||||||
start: Date;
|
start: Date;
|
||||||
@@ -27,7 +27,7 @@ export interface EmployeeDetail extends Employee {
|
|||||||
participants: Participant[];
|
participants: Participant[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapEmployeeReponseToEmployee(data: EmployeeReponse): Employee {
|
export function mapEmployeeReponseToEmployee(data: EmployeeResponse): User {
|
||||||
const names = data.pyUserName.split(' ');
|
const names = data.pyUserName.split(' ');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Employee } from './employee.model';
|
import { User } from './employee.model';
|
||||||
import { Participant } from './participant.model';
|
import { Participant } from './participant.model';
|
||||||
|
|
||||||
export interface SortBy {
|
export interface SortBy {
|
||||||
key: keyof Participant | keyof Employee;
|
key: keyof Participant | keyof User;
|
||||||
reverse: boolean;
|
reverse: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,23 @@
|
|||||||
|
import { UserResponse } from './api/user-response.model';
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
fullName: string;
|
||||||
|
userName: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapUserReponseToUser(data: UserResponse): User {
|
||||||
|
return {
|
||||||
|
id: data.pyUserIdentifier,
|
||||||
|
lastName: data.pyLastName,
|
||||||
|
firstName: data.pyFirstName,
|
||||||
|
fullName: `${data.pyFirstName} ${data.pyLastName}`,
|
||||||
|
userName: data.pyUserName,
|
||||||
|
phone: data.pyTelephone,
|
||||||
|
email: data.pyAddresses.Email.pyEmailAddress,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
|
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
|
||||||
import { Employee } from '@dafa-models/employee.model';
|
import { User } from '@dafa-models/employee.model';
|
||||||
import { Participant } from '@dafa-models/participant.model';
|
import { Participant } from '@dafa-models/participant.model';
|
||||||
import { EmployeeService } from '@dafa-services/api/employee.service';
|
import { EmployeeService } from '@dafa-services/api/employee.service';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
@@ -13,7 +13,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class EmployeeCardComponent extends UnsubscribeDirective {
|
export class EmployeeCardComponent extends UnsubscribeDirective {
|
||||||
detailedEmployeeData$: Observable<Employee>;
|
detailedEmployeeData$: Observable<User>;
|
||||||
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
|
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
|
||||||
|
|
||||||
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
|
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
<th scope="row">
|
<th scope="row">
|
||||||
<a [routerLink]="employees.id" class="employees-list__link">{{ employees.fullName }}</a>
|
<a [routerLink]="employees.id" class="employees-list__link">{{ employees.fullName }}</a>
|
||||||
</th>
|
</th>
|
||||||
<td>{{ employees.service }}</td>
|
<td>{{ employees.service || '-' }}</td>
|
||||||
<td>{{ employees.kommun }}</td>
|
<td>{{ employees.kommun || '-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { Employee } from '@dafa-models/employee.model';
|
import { User } from '@dafa-models/employee.model';
|
||||||
import { SortBy } from '@dafa-models/sort-by.model';
|
import { SortBy } from '@dafa-models/sort-by.model';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
@@ -10,9 +10,9 @@ import { BehaviorSubject } from 'rxjs';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class EmployeesListComponent {
|
export class EmployeesListComponent {
|
||||||
@Input() employees: Employee[];
|
@Input() employees: User[];
|
||||||
@Input() sortBy: SortBy | null;
|
@Input() sortBy: SortBy | null;
|
||||||
@Output() sorted = new EventEmitter<keyof Employee>();
|
@Output() sorted = new EventEmitter<keyof User>();
|
||||||
|
|
||||||
private _currentPage$ = new BehaviorSubject<number>(1);
|
private _currentPage$ = new BehaviorSubject<number>(1);
|
||||||
private _employeesPerPage = 10;
|
private _employeesPerPage = 10;
|
||||||
@@ -27,7 +27,7 @@ export class EmployeesListComponent {
|
|||||||
return Math.ceil(this.employees.length / this._employeesPerPage);
|
return Math.ceil(this.employees.length / this._employeesPerPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
get pagedEmployees(): Employee[] {
|
get pagedEmployees(): User[] {
|
||||||
return [...this.employees].slice(this.currentResultStart - 1, this.currentResultEnd - 1);
|
return [...this.employees].slice(this.currentResultStart - 1, this.currentResultEnd - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export class EmployeesListComponent {
|
|||||||
return this.currentResultStart + this._employeesPerPage;
|
return this.currentResultStart + this._employeesPerPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSort(key: keyof Employee): void {
|
handleSort(key: keyof User): void {
|
||||||
this.sorted.emit(key);
|
this.sorted.emit(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { IconType } from '@dafa-enums/icon-type.enum';
|
import { IconType } from '@dafa-enums/icon-type.enum';
|
||||||
import { Employee } from '@dafa-models/employee.model';
|
import { User } from '@dafa-models/employee.model';
|
||||||
import { SortBy } from '@dafa-models/sort-by.model';
|
import { SortBy } from '@dafa-models/sort-by.model';
|
||||||
import { EmployeeService } from '@dafa-services/api/employee.service';
|
import { EmployeeService } from '@dafa-services/api/employee.service';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
@@ -13,7 +13,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class EmployeesComponent {
|
export class EmployeesComponent {
|
||||||
private _searchValue$ = new BehaviorSubject<string>('');
|
private _searchValue$ = new BehaviorSubject<string>('');
|
||||||
filteredEmployees$: Observable<Employee[]> = this.employeeService.filteredEmployees$;
|
filteredEmployees$: Observable<User[]> = this.employeeService.filteredEmployees$;
|
||||||
employeesSortBy$: Observable<SortBy | null> = this.employeeService.employeesSortBy$;
|
employeesSortBy$: Observable<SortBy | null> = this.employeeService.employeesSortBy$;
|
||||||
iconType = IconType;
|
iconType = IconType;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export class EmployeesComponent {
|
|||||||
this._searchValue$.next($event.detail.target.value);
|
this._searchValue$.next($event.detail.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEmployeesSort(key: keyof Employee): void {
|
handleEmployeesSort(key: keyof User): void {
|
||||||
this.employeeService.setEmployeesSortKey(key);
|
this.employeeService.setEmployeesSortKey(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { environment } from '@dafa-environment';
|
import { environment } from '@dafa-environment';
|
||||||
import { Employee, EmployeeDetail, mapEmployeeReponseToEmployee } from '@dafa-models/employee.model';
|
import { EmployeeResponse } from '@dafa-models/api/employee-response.model';
|
||||||
|
import { EmployeeDetail, mapEmployeeReponseToEmployee, User } from '@dafa-models/employee.model';
|
||||||
import { SortBy } from '@dafa-models/sort-by.model';
|
import { SortBy } from '@dafa-models/sort-by.model';
|
||||||
import { sort } from '@dafa-utils/sort.util';
|
import { sort } from '@dafa-utils/sort.util';
|
||||||
import { BehaviorSubject, combineLatest, Observable, throwError } from 'rxjs';
|
import { BehaviorSubject, combineLatest, Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
|
||||||
function filterEmployees(employees: Employee[], searchFilter: string): Employee[] {
|
function filterEmployees(employees: User[], searchFilter: string): User[] {
|
||||||
return employees.filter(person => person.fullName.toLowerCase().includes(searchFilter.toLowerCase()));
|
return employees.filter(person => person.fullName.toLowerCase().includes(searchFilter.toLowerCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ function filterEmployees(employees: Employee[], searchFilter: string): Employee[
|
|||||||
})
|
})
|
||||||
export class EmployeeService {
|
export class EmployeeService {
|
||||||
private _employeesApiUrl = `${environment.apiBase}/D_pxOperatorsList`;
|
private _employeesApiUrl = `${environment.apiBase}/D_pxOperatorsList`;
|
||||||
private _allEmployees$: Observable<Employee[]> = this.httpClient
|
private _allEmployees$: Observable<User[]> = this.httpClient
|
||||||
.get<any>(this._employeesApiUrl, {
|
.get<{ pxResults: EmployeeResponse[] }>(this._employeesApiUrl, {
|
||||||
headers: environment.apiHeaders,
|
headers: environment.apiHeaders,
|
||||||
})
|
})
|
||||||
.pipe(map(({ pxResults }) => pxResults.map(result => mapEmployeeReponseToEmployee(result))));
|
.pipe(map(({ pxResults }) => pxResults.map(result => mapEmployeeReponseToEmployee(result))));
|
||||||
@@ -27,11 +28,11 @@ export class EmployeeService {
|
|||||||
private _searchFilter$ = new BehaviorSubject<string>('');
|
private _searchFilter$ = new BehaviorSubject<string>('');
|
||||||
public searchFilter$: Observable<string> = this._searchFilter$.asObservable();
|
public searchFilter$: Observable<string> = this._searchFilter$.asObservable();
|
||||||
|
|
||||||
private _filteredEmployees$: Observable<Employee[]> = combineLatest([this._allEmployees$, this._searchFilter$]).pipe(
|
private _filteredEmployees$: Observable<User[]> = combineLatest([this._allEmployees$, this._searchFilter$]).pipe(
|
||||||
map(([employees, searchFilter]) => filterEmployees(employees, searchFilter))
|
map(([employees, searchFilter]) => filterEmployees(employees, searchFilter))
|
||||||
);
|
);
|
||||||
|
|
||||||
public filteredEmployees$: Observable<Employee[]> = combineLatest([
|
public filteredEmployees$: Observable<User[]> = combineLatest([
|
||||||
this._filteredEmployees$,
|
this._filteredEmployees$,
|
||||||
this._employeesSortBy$,
|
this._employeesSortBy$,
|
||||||
]).pipe(
|
]).pipe(
|
||||||
@@ -42,15 +43,15 @@ export class EmployeeService {
|
|||||||
|
|
||||||
constructor(private httpClient: HttpClient) {}
|
constructor(private httpClient: HttpClient) {}
|
||||||
|
|
||||||
public getDetailedEmployeeData(id: string): Observable<Employee> {
|
public getDetailedEmployeeData(id: string): Observable<User> {
|
||||||
return this.httpClient.get<Employee>(`${this._employeesApiUrl}/${id}`, { params: { _embed: 'participants' } });
|
return this.httpClient.get<User>(`${this._employeesApiUrl}/${id}`, { params: { _embed: 'participants' } });
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSearchFilter(value: string) {
|
public setSearchFilter(value: string) {
|
||||||
this._searchFilter$.next(value);
|
this._searchFilter$.next(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setEmployeesSortKey(key: keyof Employee) {
|
public setEmployeesSortKey(key: keyof User) {
|
||||||
const currentSortBy = this._employeesSortBy$.getValue();
|
const currentSortBy = this._employeesSortBy$.getValue();
|
||||||
const reverse = currentSortBy?.key === key ? !currentSortBy.reverse : false;
|
const reverse = currentSortBy?.key === key ? !currentSortBy.reverse : false;
|
||||||
this._employeesSortBy$.next({ key, reverse });
|
this._employeesSortBy$.next({ key, reverse });
|
||||||
|
|||||||
21
apps/dafa-web/src/app/services/api/user.service.ts
Normal file
21
apps/dafa-web/src/app/services/api/user.service.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from '@dafa-environment';
|
||||||
|
import { UserResponse } from '@dafa-models/api/user-response.model';
|
||||||
|
import { mapUserReponseToUser, User } from '@dafa-models/user.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class UserService {
|
||||||
|
private _userApiUrl = `${environment.apiBase}/D_OperatorID`;
|
||||||
|
public currentUser$: Observable<User> = this.httpClient
|
||||||
|
.get<UserResponse>(this._userApiUrl, {
|
||||||
|
headers: environment.apiHeaders,
|
||||||
|
})
|
||||||
|
.pipe(map(response => mapUserReponseToUser(response)));
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient) {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user