ing
This commit is contained in:
parent
d191da1b19
commit
b4b752c227
|
@ -5,8 +5,16 @@
|
||||||
<div class="ui-g">
|
<div class="ui-g">
|
||||||
<div class="ui-g-12 ui-md-3">
|
<div class="ui-g-12 ui-md-3">
|
||||||
<p-accordion (onClose)="onTabClose($event)" (onOpen)="OnTabOpen($event)">
|
<p-accordion (onClose)="onTabClose($event)" (onOpen)="OnTabOpen($event)">
|
||||||
<p-accordionTab header="Discovery Search Config Area" [selected]="true">
|
<p-accordionTab header="Probe Select Area" [selected]="true">
|
||||||
<of-discovery-search-config (discoverySearchStartClick)="onDiscoveryStart()" (selectProbe)="onSelectedProbe($event)"></of-discovery-search-config>
|
<of-probe-selector
|
||||||
|
[preProbe]="probeHosts"
|
||||||
|
(probeSelected)="onSelectedProbe($event)"
|
||||||
|
></of-probe-selector>
|
||||||
|
</p-accordionTab>
|
||||||
|
<p-accordionTab header="Discovery Search Config Area" >
|
||||||
|
<of-discovery-search-config
|
||||||
|
(discoverySearchStartClick)="onDiscoveryStart()"
|
||||||
|
(selectProbe)="onSelectedProbe($event)"></of-discovery-search-config>
|
||||||
</p-accordionTab>
|
</p-accordionTab>
|
||||||
<p-accordionTab header="Result Filter Area">
|
<p-accordionTab header="Result Filter Area">
|
||||||
<of-discovery-search-filter></of-discovery-search-filter>
|
<of-discovery-search-filter></of-discovery-search-filter>
|
||||||
|
@ -19,4 +27,4 @@
|
||||||
<of-discovery-search-result [probe]="selectedProbe"></of-discovery-search-result>
|
<of-discovery-search-result [probe]="selectedProbe"></of-discovery-search-result>
|
||||||
</p-panel>
|
</p-panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {
|
import {
|
||||||
AfterContentInit, Component,
|
AfterContentInit, Component, Input,
|
||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {Probe} from '@overflow/commons-typescript/model/probe';
|
import {Probe} from '@overflow/commons-typescript/model/probe';
|
||||||
|
@ -10,6 +10,8 @@ import {Probe} from '@overflow/commons-typescript/model/probe';
|
||||||
})
|
})
|
||||||
export class DiscoveryComponent implements OnInit, AfterContentInit {
|
export class DiscoveryComponent implements OnInit, AfterContentInit {
|
||||||
|
|
||||||
|
@Input() probeHosts;
|
||||||
|
|
||||||
private tabIdx: number;
|
private tabIdx: number;
|
||||||
selectedProbe: Probe;
|
selectedProbe: Probe;
|
||||||
|
|
||||||
|
@ -43,4 +45,8 @@ export class DiscoveryComponent implements OnInit, AfterContentInit {
|
||||||
console.log(probe);
|
console.log(probe);
|
||||||
this.selectedProbe = probe;
|
this.selectedProbe = probe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onProbeSelect(probe) {
|
||||||
|
console.log(probe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,9 @@ import {
|
||||||
Component, OnInit, Input, AfterContentInit, Output,
|
Component, OnInit, Input, AfterContentInit, Output,
|
||||||
EventEmitter, OnDestroy, ViewChild
|
EventEmitter, OnDestroy, ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Store, select, StateObservable } from '@ngrx/store';
|
|
||||||
import { RPCClientError } from '@loafer/ng-rpc';
|
|
||||||
|
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { Probe } from '@overflow/commons-typescript/model/probe';
|
import {Probe, ProbeHost} from '@overflow/commons-typescript/model/probe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-probe-selector',
|
selector: 'of-probe-selector',
|
||||||
|
@ -14,31 +12,18 @@ import { Probe } from '@overflow/commons-typescript/model/probe';
|
||||||
})
|
})
|
||||||
export class ProbeSelectorComponent implements OnInit, AfterContentInit, OnDestroy {
|
export class ProbeSelectorComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||||
|
|
||||||
@Input() preProbe: Probe;
|
@Input() preProbe: ProbeHost;
|
||||||
probesSubscription$: Subscription;
|
|
||||||
probes$: StateObservable;
|
|
||||||
probes: Probe[];
|
probes: Probe[];
|
||||||
selected: Probe;
|
selected: Probe;
|
||||||
|
|
||||||
@Output() probeSelected = new EventEmitter<Probe>();
|
@Output() probeSelected = new EventEmitter<Probe>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
// private listStore: Store<ListStore.State>,
|
|
||||||
) {
|
) {
|
||||||
// this.probes$ = listStore.pipe(select(ListSelector.select('probes')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.probesSubscription$ = this.probes$.subscribe (
|
|
||||||
(list: Probe[]) => {
|
|
||||||
if (list !== null) {
|
|
||||||
this.probes = list;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error: RPCClientError) => {
|
|
||||||
console.log(error.response.message);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
|
@ -46,26 +31,29 @@ export class ProbeSelectorComponent implements OnInit, AfterContentInit, OnDestr
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.probesSubscription$) {
|
|
||||||
this.probesSubscription$.unsubscribe();
|
|
||||||
}
|
|
||||||
this.selected = null;
|
this.selected = null;
|
||||||
this.probes = null;
|
this.probes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getProbes() {
|
getProbes() {
|
||||||
// this.listStore.select(AuthSelector.select('domain')).subscribe(
|
|
||||||
// (domain: Domain) => {
|
|
||||||
// this.listStore.dispatch(new ListStore.ReadAllByDomain(domain));
|
|
||||||
// },
|
|
||||||
// (error) => {
|
|
||||||
// console.log(error);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onProbeSelect(event) {
|
onProbeSelect(event) {
|
||||||
this.selected = event.value;
|
this.selected = event.value;
|
||||||
this.probeSelected.emit(this.selected);
|
this.probeSelected.emit(this.selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(obj: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,36 @@
|
||||||
<div class="ui-g">
|
<div class="ui-g">
|
||||||
|
|
||||||
<!--<form [formGroup]="discoveryFormGroup" (ngSubmit)="discoveryStartClick()" >-->
|
<!--<form [formGroup]="discoveryFormGroup" (ngSubmit)="discoveryStartClick(discoveryFormGroup)" >-->
|
||||||
<div class="ui-g-12">
|
<!--<div class="ui-g-12">-->
|
||||||
<label>Probe</label>
|
<!--<label>Probe</label>-->
|
||||||
</div>
|
<!--</div>-->
|
||||||
<div class="ui-g-12 ui-bottom-space-20">
|
<!--<div class="ui-g-12 ui-bottom-space-20">-->
|
||||||
<of-probe-selector [preProbe]="probe" (probeSelected)="onProbeSelect($event)"></of-probe-selector>
|
<!--<of-probe-selector-->
|
||||||
</div>
|
<!--[preProbe]="probe"-->
|
||||||
|
<!--(probeSelected)="onProbeSelect($event)"-->
|
||||||
|
<!--></of-probe-selector>-->
|
||||||
|
<!--</div>-->
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<label>IP Version</label>
|
<label>IP Version</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12 ui-bottom-space-20">
|
<div class="ui-g-12 ui-bottom-space-20">
|
||||||
<div class="ui-g-6 ui-g-nopad">
|
<div class="ui-g-6 ui-g-nopad">
|
||||||
<p-radioButton name="group1" value="0" label="IPv4" [(ngModel)]="ipVesion" inputId="opt1"></p-radioButton>
|
<p-radioButton
|
||||||
|
name="group1"
|
||||||
|
value="0"
|
||||||
|
label="IPv4"
|
||||||
|
[(ngModel)]="ipVesion"
|
||||||
|
inputId="opt1"
|
||||||
|
></p-radioButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-6 ui-g-nopad">
|
<div class="ui-g-6 ui-g-nopad">
|
||||||
<p-radioButton name="group1" value="1" label="IPv6" [(ngModel)]="ipVesion" inputId="opt2"></p-radioButton>
|
<p-radioButton
|
||||||
|
name="group1"
|
||||||
|
value="1"
|
||||||
|
label="IPv6"
|
||||||
|
[(ngModel)]="ipVesion"
|
||||||
|
inputId="opt2"
|
||||||
|
></p-radioButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,23 +39,43 @@
|
||||||
<input type="hidden" >
|
<input type="hidden" >
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<of-ip-input [hostIp]="startHostIp" (inputIp)="onInputIP($event, 0)" [title]="'Start'"></of-ip-input>
|
<of-ip-input
|
||||||
|
[hostIp]="startHostIp"
|
||||||
|
(inputIp)="onInputIP($event, 0)"
|
||||||
|
[title]="'Start'"
|
||||||
|
></of-ip-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<of-ip-input [hostIp]="endHostIp" (inputIp)="onInputIP($event, 1)" [title]="'End'"></of-ip-input>
|
<of-ip-input
|
||||||
|
[hostIp]="endHostIp"
|
||||||
|
(inputIp)="onInputIP($event, 1)"
|
||||||
|
[title]="'End'"></of-ip-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12 ui-bottom-space-20">
|
<div class="ui-g-12 ui-bottom-space-20">
|
||||||
<of-ip-input [hostIp]="excludeHostIp" (inputIp)="onInputIP($event, 2)" [title]="'Exclude'"></of-ip-input>
|
<of-ip-input
|
||||||
|
[hostIp]="excludeHostIp"
|
||||||
|
(inputIp)="onInputIP($event, 2)"
|
||||||
|
[title]="'Exclude'"></of-ip-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<label>Port type</label>
|
<label>Port type</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12 ui-bottom-space-20">
|
<div class="ui-g-12 ui-bottom-space-20">
|
||||||
<div class="ui-g-6 ui-g-nopad">
|
<div class="ui-g-6 ui-g-nopad">
|
||||||
<p-radioButton name="group2" value="0" label="TCP" [(ngModel)]="portType" inputId="opt3"></p-radioButton>
|
<p-checkbox
|
||||||
|
name="group2"
|
||||||
|
value="0"
|
||||||
|
label="TCP"
|
||||||
|
[(ngModel)]="selectPortTypes"
|
||||||
|
inputId="tcp"></p-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-6 ui-g-nopad">
|
<div class="ui-g-6 ui-g-nopad">
|
||||||
<p-radioButton name="group2" value="1" label="UDP" [(ngModel)]="portType" inputId="opt4"></p-radioButton>
|
<p-checkbox
|
||||||
|
name="group2"
|
||||||
|
value="1"
|
||||||
|
label="UDP"
|
||||||
|
[(ngModel)]="selectPortTypes"
|
||||||
|
inputId="udp"></p-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -49,13 +84,26 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12 ui-g-nopad ui-bottom-space-20">
|
<div class="ui-g-12 ui-g-nopad ui-bottom-space-20">
|
||||||
<div class="ui-g-4">
|
<div class="ui-g-4">
|
||||||
<p-inputMask slotChar=" " mask="9999" [(ngModel)]="startPort" placeholder="Start" [autoClear]="false"></p-inputMask>
|
<p-inputMask
|
||||||
|
slotChar=" "
|
||||||
|
mask="9999"
|
||||||
|
[(ngModel)]="startPort"
|
||||||
|
placeholder="Start"
|
||||||
|
[autoClear]="false"></p-inputMask>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-4">
|
<div class="ui-g-4">
|
||||||
<p-inputMask mask="9999" [(ngModel)]="endPort" placeholder="End" [autoClear]="false"></p-inputMask>
|
<p-inputMask
|
||||||
|
mask="9999"
|
||||||
|
[(ngModel)]="endPort"
|
||||||
|
placeholder="End"
|
||||||
|
[autoClear]="false"></p-inputMask>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-4">
|
<div class="ui-g-4">
|
||||||
<p-inputMask mask="9999" [(ngModel)]="excludePort" placeholder="Exclude" [autoClear]="false"></p-inputMask>
|
<p-inputMask
|
||||||
|
mask="9999"
|
||||||
|
[(ngModel)]="excludePort"
|
||||||
|
placeholder="Exclude"
|
||||||
|
[autoClear]="false"></p-inputMask>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -66,7 +114,7 @@
|
||||||
<of-service-selector [(includeServices)]="includeServices"></of-service-selector>
|
<of-service-selector [(includeServices)]="includeServices"></of-service-selector>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12" dir="rtl">
|
<div class="ui-g-12" dir="rtl">
|
||||||
<button type="submit" label="Discovery Start" pButton class="ui-button-width-fit" ></button>
|
<button type="submit" label="Discovery Start" pButton class="ui-button-width-fit" (click)="discoveryStartClick()" ></button>
|
||||||
</div>
|
</div>
|
||||||
<!--</form>-->
|
<!--</form>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
FormBuilder,
|
FormBuilder,
|
||||||
FormGroup
|
FormGroup, Validators
|
||||||
} from '@angular/forms';
|
} from '@angular/forms';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -21,7 +21,6 @@ export class SearchConfigComponent implements OnInit, AfterContentInit {
|
||||||
discoveryFormGroup: FormGroup;
|
discoveryFormGroup: FormGroup;
|
||||||
|
|
||||||
ipVesion: number;
|
ipVesion: number;
|
||||||
portType: number;
|
|
||||||
|
|
||||||
startIP: string;
|
startIP: string;
|
||||||
endIP: string;
|
endIP: string;
|
||||||
|
@ -30,12 +29,12 @@ export class SearchConfigComponent implements OnInit, AfterContentInit {
|
||||||
endPort: string;
|
endPort: string;
|
||||||
excludePort: string;
|
excludePort: string;
|
||||||
|
|
||||||
probe: number;
|
|
||||||
|
|
||||||
startHostIp: string;
|
startHostIp: string;
|
||||||
endHostIp: string;
|
endHostIp: string;
|
||||||
excludeHostIp: string;
|
excludeHostIp: string;
|
||||||
|
|
||||||
|
selectPortTypes: string[] = ['0'];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
) {
|
) {
|
||||||
|
@ -43,7 +42,6 @@ export class SearchConfigComponent implements OnInit, AfterContentInit {
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.ipVesion = 0;
|
this.ipVesion = 0;
|
||||||
this.portType = 0;
|
|
||||||
this.initForm();
|
this.initForm();
|
||||||
// this.hostIp = '192.168.1.10';
|
// this.hostIp = '192.168.1.10';
|
||||||
}
|
}
|
||||||
|
@ -53,7 +51,16 @@ export class SearchConfigComponent implements OnInit, AfterContentInit {
|
||||||
|
|
||||||
initForm() {
|
initForm() {
|
||||||
// this.discoveryFormGroup = this.formBuilder.group({
|
// this.discoveryFormGroup = this.formBuilder.group({
|
||||||
//
|
// probeSelect: [null],
|
||||||
|
// IPType: [null],
|
||||||
|
// startIP:[null],
|
||||||
|
// endIP: [null],
|
||||||
|
// exIP: [null],
|
||||||
|
// portType: [null],
|
||||||
|
// startPort: [null],
|
||||||
|
// endPort: [null],
|
||||||
|
// exPort: [null],
|
||||||
|
// services: [null]
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,11 +68,6 @@ export class SearchConfigComponent implements OnInit, AfterContentInit {
|
||||||
this.discoverySearchStartClick.emit();
|
this.discoverySearchStartClick.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
onProbeSelect(probe) {
|
|
||||||
console.log(probe);
|
|
||||||
this.selectProbe.emit(probe);
|
|
||||||
}
|
|
||||||
|
|
||||||
onInputIP(event, idx) {
|
onInputIP(event, idx) {
|
||||||
console.log(idx);
|
console.log(idx);
|
||||||
console.log(event.target.data);
|
console.log(event.target.data);
|
||||||
|
|
|
@ -29,25 +29,25 @@ export class ServiceSelectorComponent implements OnInit, AfterContentInit, OnDes
|
||||||
constructor(
|
constructor(
|
||||||
private listStore: Store<ListStore.State>,
|
private listStore: Store<ListStore.State>,
|
||||||
) {
|
) {
|
||||||
this.crawlers$ = listStore.pipe(select(ReadAllCrawlerSelector.select('metaCrawlerList')));
|
// this.crawlers$ = listStore.pipe(select(ReadAllCrawlerSelector.select('metaCrawlerList')));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.crawlersSubscription$ = this.crawlers$.subscribe(
|
// this.crawlersSubscription$ = this.crawlers$.subscribe(
|
||||||
(list: MetaCrawler[]) => {
|
// (list: MetaCrawler[]) => {
|
||||||
if (list !== null) {
|
// if (list !== null) {
|
||||||
this.crawlers = [];
|
// this.crawlers = [];
|
||||||
this.crawlers = list;
|
// this.crawlers = list;
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
(error: RPCClientError) => {
|
// (error: RPCClientError) => {
|
||||||
console.log(error);
|
// console.log(error);
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
this.listStore.dispatch(new ListStore.ReadAll());
|
// this.listStore.dispatch(new ListStore.ReadAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<of-discovery></of-discovery>
|
<of-discovery [probeHosts]="probeHosts$ | async"></of-discovery>
|
||||||
|
|
|
@ -2,8 +2,15 @@ import {
|
||||||
AfterContentInit, Component, Input,
|
AfterContentInit, Component, Input,
|
||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { select, StateObservable } from '@ngrx/store';
|
import { select, Store} from '@ngrx/store';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Probe, ProbeHost } from '@overflow/commons-typescript/model/probe';
|
||||||
|
|
||||||
|
import { AuthSelector } from '@overflow/member/store';
|
||||||
|
import { Domain } from '@overflow/commons-typescript/model/domain';
|
||||||
|
import * as ProbeEntityStore from '@overflow/probe/store/entity/probe';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import { ProbeEntitySelector } from '@overflow/probe/store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-discovery-container',
|
selector: 'of-discovery-container',
|
||||||
|
@ -18,15 +25,26 @@ export class DiscoveryContainerComponent implements OnInit, AfterContentInit {
|
||||||
// get service list
|
// get service list
|
||||||
@Input() hostID;
|
@Input() hostID;
|
||||||
|
|
||||||
|
probeHosts$: Observable<Probe[]>;
|
||||||
|
selectProbes?: Probe[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private store: Store<ProbeEntityStore.State>
|
||||||
) {
|
) {
|
||||||
if (this.hostID > 0 && this.hostID !== undefined ) {
|
this.probeHosts$ = store.pipe(select(ProbeEntitySelector.selectAll));
|
||||||
console.log('ddddddddddddddddddddddddddddddddddddddd');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.store.select(AuthSelector.select('domain')).subscribe(
|
||||||
|
(domain: Domain) => {
|
||||||
|
this.store.dispatch(new ProbeEntityStore.ReadAllByDomainID(domain.id));
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user