feat: added pentest status selection
This commit is contained in:
parent
c1293b4da1
commit
de659e3293
|
@ -2,22 +2,35 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<nb-tabset>
|
<nb-tabset>
|
||||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'global.action.info' | translate }}">
|
<nb-tab class="pentest-tabset" tabTitle="{{ 'global.action.info' | translate }}">
|
||||||
<app-pentest-info [pentestInfo$] = pentest$></app-pentest-info>
|
<app-pentest-info [pentestInfo$]=pentest$></app-pentest-info>
|
||||||
</nb-tab>
|
</nb-tab>
|
||||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.findings' | translate }}" badgeText="{{currentNumberOfFindings$.getValue()}}" badgeStatus="danger">
|
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.findings' | translate }}"
|
||||||
<app-pentest-findings [pentestInfo$] = pentest$></app-pentest-findings>
|
badgeText="{{currentNumberOfFindings$.getValue()}}" badgeStatus="danger">
|
||||||
|
<app-pentest-findings [pentestInfo$]=pentest$></app-pentest-findings>
|
||||||
</nb-tab>
|
</nb-tab>
|
||||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.comments' | translate }}" badgeText="{{currentNumberOfComments$.getValue()}}" badgeStatus="info">
|
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.comments' | translate }}"
|
||||||
<app-pentest-comments [pentestInfo$] = pentest$></app-pentest-comments>
|
badgeText="{{currentNumberOfComments$.getValue()}}" badgeStatus="info">
|
||||||
|
<app-pentest-comments [pentestInfo$]=pentest$></app-pentest-comments>
|
||||||
</nb-tab>
|
</nb-tab>
|
||||||
</nb-tabset>
|
</nb-tabset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayoutAlign="end end" class="content-footer">
|
<div fxLayoutAlign="end end" class="content-footer">
|
||||||
|
<!-- Pentest Status Selection -->
|
||||||
|
<div class="pentest-status-dialog">
|
||||||
|
<nb-select class="status"
|
||||||
|
[(selected)]="currentStatus"
|
||||||
|
shape="round" filled
|
||||||
|
status="{{getPentestFillStatus(currentStatus)}}">
|
||||||
|
<nb-option *ngFor="let status of statusTexts" [value]="status.value">
|
||||||
|
{{ status.translationText | translate }}
|
||||||
|
</nb-option>
|
||||||
|
</nb-select>
|
||||||
|
</div>
|
||||||
<button nbButton
|
<button nbButton
|
||||||
class="save-pentest-button"
|
class="save-pentest-button"
|
||||||
status="primary"
|
status="primary"
|
||||||
[disabled]="!pentestChanged$.getValue()"
|
[disabled]="!pentestStatusChanged()"
|
||||||
title="{{ 'global.action.save' | translate }}"
|
title="{{ 'global.action.save' | translate }}"
|
||||||
(click)="onClickSavePentest()">
|
(click)="onClickSavePentest()">
|
||||||
<span class="exit-element-text"> {{ 'global.action.save' | translate }} </span>
|
<span class="exit-element-text"> {{ 'global.action.save' | translate }} </span>
|
||||||
|
|
|
@ -14,6 +14,28 @@
|
||||||
|
|
||||||
.content-footer {
|
.content-footer {
|
||||||
height: 5%;
|
height: 5%;
|
||||||
|
|
||||||
|
.pentest-status-dialog {
|
||||||
|
margin: 1rem 2.25rem 1rem 0;
|
||||||
|
|
||||||
|
.status {
|
||||||
|
width: 12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic {
|
||||||
|
background-color: nb-theme(color-basic-default);
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
background-color: nb-theme(color-info-default);
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
background-color: nb-theme(color-warning-default);
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
background-color: nb-theme(color-success-default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.save-pentest-button {
|
.save-pentest-button {
|
||||||
margin: 1rem 6rem 1rem 0;
|
margin: 1rem 6rem 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||||
import {BehaviorSubject} from 'rxjs';
|
import {BehaviorSubject} from 'rxjs';
|
||||||
import {Store} from '@ngxs/store';
|
import {Store} from '@ngxs/store';
|
||||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||||
import {Pentest} from '@shared/models/pentest.model';
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||||
|
import {StatusText} from '@shared/widgets/status-tag/status-tag.component';
|
||||||
|
import {PentestService} from '@shared/services/pentest.service';
|
||||||
|
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -21,7 +25,24 @@ export class PentestContentComponent implements OnInit {
|
||||||
currentNumberOfFindings$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
currentNumberOfFindings$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
||||||
currentNumberOfComments$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
currentNumberOfComments$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
||||||
|
|
||||||
constructor(private store: Store) { }
|
// Pentest Status Handler
|
||||||
|
currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
||||||
|
private initialPentestStatus: PentestStatus;
|
||||||
|
status = PentestStatus;
|
||||||
|
readonly statusTexts: Array<StatusText> = [
|
||||||
|
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
||||||
|
/* ToDo: Disabled not needed inside pentest */
|
||||||
|
/*{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},*/
|
||||||
|
{value: PentestStatus.OPEN, translationText: 'pentest.statusText.open'},
|
||||||
|
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
||||||
|
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly pentestService: PentestService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private store: Store) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.store.selectOnce(ProjectState.pentest).pipe(
|
this.store.selectOnce(ProjectState.pentest).pipe(
|
||||||
|
@ -29,6 +50,8 @@ export class PentestContentComponent implements OnInit {
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: (selectedPentest: Pentest) => {
|
next: (selectedPentest: Pentest) => {
|
||||||
this.pentest$.next(selectedPentest);
|
this.pentest$.next(selectedPentest);
|
||||||
|
this.currentStatus = selectedPentest.status;
|
||||||
|
this.initialPentestStatus = selectedPentest.status;
|
||||||
const findings = selectedPentest.findingsIds ? selectedPentest.findingsIds.length : 0;
|
const findings = selectedPentest.findingsIds ? selectedPentest.findingsIds.length : 0;
|
||||||
this.currentNumberOfFindings$.next(findings);
|
this.currentNumberOfFindings$.next(findings);
|
||||||
const comments = selectedPentest.commentsIds ? selectedPentest.commentsIds.length : 0;
|
const comments = selectedPentest.commentsIds ? selectedPentest.commentsIds.length : 0;
|
||||||
|
@ -41,6 +64,59 @@ export class PentestContentComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickSavePentest(): void {
|
onClickSavePentest(): void {
|
||||||
console.info('to be implemented..');
|
this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
|
||||||
|
console.warn('Updated Pentest: ', this.pentest$.getValue());
|
||||||
|
this.pentestService.savePentest(this.pentest$.getValue())
|
||||||
|
.subscribe({
|
||||||
|
next: (pentest: Pentest) => {
|
||||||
|
this.notificationService.showPopup('pentest.popup.save.success', PopupType.SUCCESS);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.log(err);
|
||||||
|
this.notificationService.showPopup('pentest.popup.save.failed', PopupType.FAILURE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if initial pentest Status is different from current pentest status
|
||||||
|
*/
|
||||||
|
pentestStatusChanged(): boolean {
|
||||||
|
if (this.initialPentestStatus !== this.currentStatus) {
|
||||||
|
this.pentestChanged$.next(true);
|
||||||
|
} else {
|
||||||
|
this.pentestChanged$.next(false);
|
||||||
|
}
|
||||||
|
return this.pentestChanged$.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the correct nb-status for current pentest-status
|
||||||
|
*/
|
||||||
|
getPentestFillStatus(value: PentestStatus): string {
|
||||||
|
let pentestFillStatus;
|
||||||
|
switch (value) {
|
||||||
|
case PentestStatus.NOT_STARTED: {
|
||||||
|
pentestFillStatus = 'basic';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.OPEN: {
|
||||||
|
pentestFillStatus = 'info';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.IN_PROGRESS: {
|
||||||
|
pentestFillStatus = 'warning';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.COMPLETED: {
|
||||||
|
pentestFillStatus = 'success';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
pentestFillStatus = 'basic';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pentestFillStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {RouterModule} from '@angular/router';
|
import {RouterModule} from '@angular/router';
|
||||||
import {PentestComponent} from './pentest.component';
|
import {PentestComponent} from './pentest.component';
|
||||||
import {NbButtonModule, NbCardModule, NbLayoutModule, NbTabsetModule, NbTreeGridModule} from '@nebular/theme';
|
import {NbButtonModule, NbCardModule, NbLayoutModule, NbSelectModule, NbTabsetModule, NbTreeGridModule} from '@nebular/theme';
|
||||||
import { PentestHeaderComponent } from './pentest-header/pentest-header.component';
|
import { PentestHeaderComponent } from './pentest-header/pentest-header.component';
|
||||||
import { PentestContentComponent } from './pentest-content/pentest-content.component';
|
import { PentestContentComponent } from './pentest-content/pentest-content.component';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
|
@ -42,7 +42,8 @@ import {FindingDialogModule} from '@shared/modules/finding-dialog/finding-dialog
|
||||||
NbTabsetModule,
|
NbTabsetModule,
|
||||||
NbTreeGridModule,
|
NbTreeGridModule,
|
||||||
SeverityTagModule,
|
SeverityTagModule,
|
||||||
FindingDialogModule
|
FindingDialogModule,
|
||||||
|
NbSelectModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PentestModule {
|
export class PentestModule {
|
||||||
|
|
|
@ -174,6 +174,15 @@
|
||||||
"in_progress": "In Bearbeitung",
|
"in_progress": "In Bearbeitung",
|
||||||
"completed": "Fertig"
|
"completed": "Fertig"
|
||||||
},
|
},
|
||||||
|
"popup": {
|
||||||
|
"not.found": "Keine pentests gefunden",
|
||||||
|
"save.success": "Pentest erfolgreich gespeichert",
|
||||||
|
"save.failed": "Pentest konnte nicht gespeichert werden",
|
||||||
|
"update.success": "Pentest erfolgreich aktualisiert",
|
||||||
|
"update.failed": "Pentest konnte nicht aktualisiert werden",
|
||||||
|
"delete.success": "Pentest erfolgreich gelöscht",
|
||||||
|
"delete.failed": "Pentest konnte nicht gelöscht werden"
|
||||||
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks",
|
"001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks",
|
||||||
"002": "Fingerabdruck-Webserver",
|
"002": "Fingerabdruck-Webserver",
|
||||||
|
|
|
@ -174,6 +174,15 @@
|
||||||
"in_progress": "In progress",
|
"in_progress": "In progress",
|
||||||
"completed": "Completed"
|
"completed": "Completed"
|
||||||
},
|
},
|
||||||
|
"popup": {
|
||||||
|
"not.found": "No pentest found",
|
||||||
|
"save.success": "Pentest saved successfully",
|
||||||
|
"save.failed": "Pentest could not be saved",
|
||||||
|
"update.success": "Pentest updated successfully",
|
||||||
|
"update.failed": "Pentest could not be updated",
|
||||||
|
"delete.success": "Pentest deleted successfully",
|
||||||
|
"delete.failed": "Pentest could not be deleted"
|
||||||
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage",
|
"001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage",
|
||||||
"002": "Fingerprint Web Server",
|
"002": "Fingerprint Web Server",
|
||||||
|
|
|
@ -54,6 +54,14 @@ export class PentestService {
|
||||||
return this.http.get<Pentest[]>(`${this.apiBaseURL}`, {params: queryParams});
|
return this.http.get<Pentest[]>(`${this.apiBaseURL}`, {params: queryParams});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save Pentest
|
||||||
|
* @param pentest the information of the Pentest
|
||||||
|
*/
|
||||||
|
public savePentest(pentest: Pentest): Observable<Pentest> {
|
||||||
|
return this.http.post<Pentest>(`${this.apiBaseURL}/${pentest.id}`, pentest);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Findings for Pentest Id
|
* Get Findings for Pentest Id
|
||||||
* @param pentestId the id of the project
|
* @param pentestId the id of the project
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class StatusTagComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StatusText {
|
export interface StatusText {
|
||||||
value: string;
|
value: string;
|
||||||
translationText: string;
|
translationText: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue