diff --git a/security-c4po-angular/src/app/header/header.component.html b/security-c4po-angular/src/app/header/header.component.html
index cce961f..2b64594 100644
--- a/security-c4po-angular/src/app/header/header.component.html
+++ b/security-c4po-angular/src/app/header/header.component.html
@@ -11,6 +11,15 @@
+
+
+
+
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.scss b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.scss
index 6dc3c74..eabc9c5 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.scss
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.scss
@@ -10,33 +10,9 @@
/*nb-tab {
position: fixed;
}*/
- }
- .content-footer {
- 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 {
+ .content-footer {
+ height: 5%;
margin: 1rem 6rem 1rem 0;
}
}
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.ts
index fb98cac..cde1354 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.ts
@@ -1,17 +1,12 @@
import {Component, OnInit} from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
-import {BehaviorSubject, Observable} from 'rxjs';
-import {Select, Store} from '@ngxs/store';
+import {BehaviorSubject} from 'rxjs';
+import {Store} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
-import {Pentest, transformPentestToRequestBody} from '@shared/models/pentest.model';
-import {PentestStatus} from '@shared/models/pentest-status.model';
-import {StatusText} from '@shared/widgets/status-tag/status-tag.component';
+import {Pentest} from '@shared/models/pentest.model';
import {PentestService} from '@shared/services/pentest.service';
-import {NotificationService, PopupType} from '@shared/services/notification.service';
-import {Project} from '@shared/models/project.model';
-import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
-import {filter} from 'rxjs/operators';
+import {NotificationService} from '@shared/services/notification.service';
@UntilDestroy()
@Component({
@@ -23,28 +18,10 @@ export class PentestContentComponent implements OnInit {
// HTML only
readonly fa = FA;
- @Select(ProjectState.project)
- selectedProject$: Observable;
- selectedProjectId: string;
-
pentest$: BehaviorSubject = new BehaviorSubject(null);
- pentestChanged$: BehaviorSubject = new BehaviorSubject(false);
currentNumberOfFindings$: BehaviorSubject = new BehaviorSubject(0);
currentNumberOfComments$: BehaviorSubject = new BehaviorSubject(0);
- // Pentest Status Handler
- currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
- private initialPentestStatus: PentestStatus;
- status = PentestStatus;
- readonly statusTexts: Array = [
- {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,
@@ -52,26 +29,11 @@ export class PentestContentComponent implements OnInit {
}
ngOnInit(): void {
- this.selectedProject$.pipe(
- filter(isNotNullOrUndefined),
- untilDestroyed(this)
- ).subscribe({
- next: (project) => {
- this.selectedProjectId = project.id;
- },
- error: (err) => {
- console.error(err);
- }
- });
-
this.store.select(ProjectState.pentest).pipe(
untilDestroyed(this)
).subscribe({
next: (selectedPentest: Pentest) => {
- console.warn(selectedPentest);
this.pentest$.next(selectedPentest);
- this.currentStatus = selectedPentest.status;
- this.initialPentestStatus = selectedPentest.status;
const findings = selectedPentest.findingIds ? selectedPentest.findingIds.length : 0;
this.currentNumberOfFindings$.next(findings);
const comments = selectedPentest.commentIds ? selectedPentest.commentIds.length : 0;
@@ -82,78 +44,4 @@ export class PentestContentComponent implements OnInit {
}
});
}
-
- onClickSavePentest(): void {
- this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
- this.pentestService.savePentest(this.selectedProjectId, transformPentestToRequestBody(this.pentest$.getValue()))
- .subscribe({
- next: (pentest: Pentest) => {
- this.pentest$.next(pentest);
- this.initialPentestStatus = pentest.status;
- this.notificationService.showPopup('pentest.popup.save.success', PopupType.SUCCESS);
- },
- error: err => {
- console.log(err);
- this.notificationService.showPopup('pentest.popup.save.failed', PopupType.FAILURE);
- }
- });
- }
-
- onClickUpdatePentest(): void {
- this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
- this.pentestService.updatePentest(transformPentestToRequestBody(this.pentest$.getValue()))
- .subscribe({
- next: (pentest: Pentest) => {
- this.pentest$.next(pentest);
- this.initialPentestStatus = pentest.status;
- this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS);
- },
- error: err => {
- console.log(err);
- this.notificationService.showPopup('pentest.popup.update.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;
- }
}
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html
index 72d7498..fcd12bb 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html
@@ -19,7 +19,7 @@
{{ 'finding.severity' | translate }}
|
-
+ |
|
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss
index 51ebbfb..fc4b47e 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss
@@ -7,7 +7,8 @@
.finding-cell {
// Add style here
height: 4.5rem !important;
- max-height: 4.5rem !important;
+ // max-height: 4.5rem !important;
+ overflow: hidden;
}
.finding-cell:hover {
@@ -19,9 +20,15 @@
width: 125px;
max-width: 125px;
// border-style: none;
+ // ToDo: Fix size issue on lower screen resolution
height: 4.5rem !important;
}
+ .cell {
+ height: 4.5rem !important;
+ max-height: 4.5rem !important;
+ }
+
.border-style {
border-top-style: none;
border-left-style: none;
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.ts
index bedb3b1..5bbbbdb 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.ts
@@ -1,7 +1,7 @@
-import {Component, Input, OnInit} from '@angular/core';
+import {Component, OnInit} from '@angular/core';
import {PentestService} from '@shared/services/pentest.service';
import {BehaviorSubject, Observable} from 'rxjs';
-import {Pentest, transformPentestToRequestBody} from '@shared/models/pentest.model';
+import {Pentest} from '@shared/models/pentest.model';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {filter, mergeMap, tap} from 'rxjs/operators';
import {NotificationService, PopupType} from '@shared/services/notification.service';
@@ -18,6 +18,9 @@ import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
import {FindingDialogService} from '@shared/modules/finding-dialog/service/finding-dialog.service';
import {FindingDialogComponent} from '@shared/modules/finding-dialog/finding-dialog.component';
import {PentestStatus} from '@shared/models/pentest-status.model';
+import {Store} from '@ngxs/store';
+import {UpdatePentestFindings} from '@shared/stores/project-state/project-state.actions';
+import {ProjectState} from '@shared/stores/project-state/project-state';
@UntilDestroy()
@Component({
@@ -30,16 +33,17 @@ export class PentestFindingsComponent implements OnInit {
constructor(private readonly pentestService: PentestService,
private dataSourceBuilder: NbTreeGridDataSourceBuilder,
private notificationService: NotificationService,
- private findingDialogService: FindingDialogService) {
+ private findingDialogService: FindingDialogService,
+ private store: Store) {
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
}
- @Input()
pentestInfo$: BehaviorSubject = new BehaviorSubject(null);
+ loading$: BehaviorSubject = new BehaviorSubject(true);
// HTML only
readonly fa = FA;
- loading$: BehaviorSubject = new BehaviorSubject(true);
+ notStartedStatus: PentestStatus = PentestStatus.NOT_STARTED;
columns: Array = [
FindingColumns.FINDING_ID, FindingColumns.SEVERITY, FindingColumns.TITLE, FindingColumns.IMPACT, FindingColumns.ACTIONS
@@ -54,23 +58,35 @@ export class PentestFindingsComponent implements OnInit {
expandedGetter: (node: FindingEntry) => !!node.expanded,
};
- // HTML only
- notStartedStatus: PentestStatus = PentestStatus.NOT_STARTED;
-
ngOnInit(): void {
- this.loadFindingsData();
+ this.store.select(ProjectState.pentest).pipe(
+ untilDestroyed(this)
+ ).subscribe({
+ next: (selectedPentest: Pentest) => {
+ this.pentestInfo$.next(selectedPentest);
+ this.loadFindingsData();
+ },
+ error: err => {
+ console.error(err);
+ }
+ });
}
loadFindingsData(): void {
this.pentestService.getFindingsByPentestId(this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '')
.pipe(
untilDestroyed(this),
- filter(isNotNullOrUndefined),
+ /*filter(isNotNullOrUndefined),*/
tap(() => this.loading$.next(true))
)
.subscribe({
next: (findings: Finding[]) => {
- this.data = transformFindingsToObjectiveEntries(findings);
+ // ToDo: Handle this case before in pipe
+ if (findings) {
+ this.data = transformFindingsToObjectiveEntries(findings);
+ } else {
+ this.data = [];
+ }
this.dataSource.setData(this.data, this.getters);
this.loading$.next(false);
},
@@ -104,8 +120,8 @@ export class PentestFindingsComponent implements OnInit {
),
untilDestroyed(this)
).subscribe({
- next: () => {
- // ToDo: Parse new Counter to overview / -> dispatch to store maybe already update it
+ next: (finding) => {
+ this.store.dispatch(new UpdatePentestFindings(finding.id));
this.loadFindingsData();
this.notificationService.showPopup('finding.popup.save.success', PopupType.SUCCESS);
},
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts
index 9b19381..77007b4 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts
@@ -9,14 +9,41 @@ import {ThemeModule} from '@assets/@theme/theme.module';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from '../../../common-app.module';
import {HttpClient} from '@angular/common/http';
-import {NgxsModule} from '@ngxs/store';
-import {ProjectState} from '@shared/stores/project-state/project-state';
+import {NgxsModule, Store} from '@ngxs/store';
+import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
import {Category} from '@shared/models/category.model';
import {PentestStatus} from '@shared/models/pentest-status.model';
+const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
+ selectedProject: {
+ id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
+ client: 'E Corp',
+ title: 'Some Mock API (v1.0) Scanning',
+ createdAt: new Date('2019-01-10T09:00:00'),
+ tester: 'Novatester',
+ testingProgress: 0,
+ createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
+ },
+ // Manages Categories
+ disabledCategories: [],
+ selectedCategory: Category.INFORMATION_GATHERING,
+ // Manages Pentests of Category
+ disabledPentests: [],
+ selectedPentest: {
+ id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
+ category: Category.INFORMATION_GATHERING,
+ refNumber: 'OTF-001',
+ childEntries: [],
+ status: PentestStatus.NOT_STARTED,
+ findingIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112'],
+ commentIds: []
+ },
+};
+
describe('PentestInfoComponent', () => {
let component: PentestInfoComponent;
let fixture: ComponentFixture;
+ let store: Store;
beforeEach(async () => {
await TestBed.configureTestingModule({
@@ -44,6 +71,11 @@ describe('PentestInfoComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(PentestInfoComponent);
+ store = TestBed.inject(Store);
+ store.reset({
+ ...store.snapshot(),
+ [PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
+ });
component = fixture.componentInstance;
component.pentestInfo$.next({
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.ts
index 54df9f1..bf58159 100644
--- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.ts
@@ -3,7 +3,11 @@ import {BehaviorSubject} from 'rxjs';
import {Pentest} from '@shared/models/pentest.model';
import {getPentestInfoForObjective} from '@shared/functions/infos/get-pentest-info-for-objective';
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
+import {ProjectState} from '@shared/stores/project-state/project-state';
+import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
+import {Store} from '@ngxs/store';
+@UntilDestroy()
@Component({
selector: 'app-pentest-info',
templateUrl: './pentest-info.component.html',
@@ -11,12 +15,21 @@ import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-ke
})
export class PentestInfoComponent implements OnInit {
- @Input()
pentestInfo$: BehaviorSubject = new BehaviorSubject(null);
- constructor() { }
+ constructor(private store: Store) { }
ngOnInit(): void {
+ this.store.selectOnce(ProjectState.pentest).pipe(
+ untilDestroyed(this)
+ ).subscribe({
+ next: (selectedPentest: Pentest) => {
+ this.pentestInfo$.next(selectedPentest);
+ },
+ error: err => {
+ console.error(err);
+ }
+ });
}
getPentestHeaderForObjective(refNumber: string): string {
diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.html b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.html
index 296b165..e2962fc 100644
--- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.html
+++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.html
@@ -14,7 +14,41 @@
{{selectedProjectTitle$.getValue()}} / {{pentest$.getValue().refNumber}}
-
+
+
+
+
+
+
+
+ {{ status.translationText | translate }}
+
+
+
+
+
+
+
+
+
+
diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.scss b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.scss
index 78c5dca..2d69bf0 100644
--- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.scss
+++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.scss
@@ -4,6 +4,7 @@
.exit-button-container {
.exit-element-icon {
}
+
.exit-element-text {
padding-left: 0.5rem;
}
@@ -12,6 +13,35 @@
.pentest-status-container {
display: flex;
align-content: flex-end;
- margin-right: 0.5rem;
+ // margin-right: 0.5rem;
+ // 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 {
+ margin: 1rem 0 1rem 0;
+ }
}
}
diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts
index 6ff228b..2020be2 100644
--- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts
@@ -11,8 +11,10 @@ import {NgxsModule, Store} from '@ngxs/store';
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
import {Category} from '@shared/models/category.model';
import {PentestStatus} from '@shared/models/pentest-status.model';
+import {NotificationService} from '@shared/services/notification.service';
+import {NotificationServiceMock} from '@shared/services/notification.service.mock';
-const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
+const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
selectedProject: {
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
client: 'E Corp',
@@ -58,6 +60,9 @@ describe('PentestHeaderComponent', () => {
}),
RouterTestingModule.withRoutes([]),
NgxsModule.forRoot([ProjectState])
+ ],
+ providers: [
+ {provide: NotificationService, useValue: new NotificationServiceMock()},
]
})
.compileComponents();
diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts
index ef77635..29b91a0 100644
--- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts
+++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts
@@ -6,10 +6,13 @@ import {Store} from '@ngxs/store';
import {Router} from '@angular/router';
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
import {BehaviorSubject} from 'rxjs';
-import {PentestStatus} from '@shared/models/pentest-status.model';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {Project} from '@shared/models/project.model';
-import {Pentest} from '@shared/models/pentest.model';
+import {Pentest, transformPentestToRequestBody} from '@shared/models/pentest.model';
+import {NotificationService, PopupType} from '@shared/services/notification.service';
+import {PentestStatus} from '@shared/models/pentest-status.model';
+import {PentestService} from '@shared/services/pentest.service';
+import {StatusText} from '@shared/widgets/status-tag/status-tag.component';
@UntilDestroy()
@Component({
@@ -23,8 +26,27 @@ export class PentestHeaderComponent implements OnInit {
pentest$: BehaviorSubject = new BehaviorSubject(null);
selectedProjectTitle$: BehaviorSubject = new BehaviorSubject('');
+ pentestChanged$: BehaviorSubject = new BehaviorSubject(false);
+
+ // Pentest Status Handler
+ status = PentestStatus;
+ currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
+ private initialPentestStatus: PentestStatus;
+ // Status Text Translation Texts
+ readonly statusTexts: Array = [
+ {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'}
+ ];
+
+ selectedProjectId$: BehaviorSubject = new BehaviorSubject('');
constructor(private store: Store,
+ private pentestService: PentestService,
+ private notificationService: NotificationService,
private readonly router: Router) {
}
@@ -33,6 +55,7 @@ export class PentestHeaderComponent implements OnInit {
untilDestroyed(this)
).subscribe({
next: (selectedProject: Project) => {
+ this.selectedProjectId$.next(selectedProject.id);
this.selectedProjectTitle$.next(selectedProject?.title);
},
error: err => {
@@ -44,6 +67,8 @@ export class PentestHeaderComponent implements OnInit {
untilDestroyed(this)
).subscribe({
next: (selectedPentest: Pentest) => {
+ this.currentStatus = selectedPentest.status;
+ this.initialPentestStatus = selectedPentest.status;
this.pentest$.next(selectedPentest);
},
error: err => {
@@ -61,4 +86,76 @@ export class PentestHeaderComponent implements OnInit {
}
).finally();
}
+
+ onClickSavePentest(): void {
+ this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
+ this.pentestService.savePentest(this.selectedProjectId$.getValue(), transformPentestToRequestBody(this.pentest$.getValue()))
+ .subscribe({
+ next: (pentest: Pentest) => {
+ this.store.dispatch(new ChangePentest(pentest));
+ this.notificationService.showPopup('pentest.popup.save.success', PopupType.SUCCESS);
+ },
+ error: err => {
+ console.log(err);
+ this.notificationService.showPopup('pentest.popup.save.failed', PopupType.FAILURE);
+ }
+ });
+ }
+
+ onClickUpdatePentest(): void {
+ this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
+ this.pentestService.updatePentest(transformPentestToRequestBody(this.pentest$.getValue()))
+ .subscribe({
+ next: (pentest: Pentest) => {
+ this.store.dispatch(new ChangePentest(pentest));
+ this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS);
+ },
+ error: err => {
+ console.log(err);
+ this.notificationService.showPopup('pentest.popup.update.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;
+ }
}
diff --git a/security-c4po-angular/src/shared/services/pentest.service.ts b/security-c4po-angular/src/shared/services/pentest.service.ts
index 52cce89..7b1e2ea 100644
--- a/security-c4po-angular/src/shared/services/pentest.service.ts
+++ b/security-c4po-angular/src/shared/services/pentest.service.ts
@@ -8,8 +8,7 @@ import {Store} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {catchError, map, switchMap} from 'rxjs/operators';
import {getTempPentestsForCategory} from '@shared/functions/categories/get-temp-pentests-for-category.function';
-import {Finding, FindingDialogBody} from '@shared/models/finding.model';
-import {Severity} from '@shared/models/severity.enum';
+import {Finding} from '@shared/models/finding.model';
import {Comment} from '@shared/models/comment.model';
import {v4 as UUID} from 'uuid';
@@ -85,46 +84,43 @@ export class PentestService {
* @param pentestId the id of the project
*/
public getFindingsByPentestId(pentestId: string): Observable {
- if (pentestId) {
- return this.http.get(`${this.apiBaseURL}/${pentestId}/findings`);
- } else {
- // return of([]);
- // Todo: Remove mocked Findings
- return of([
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
- title: 'This is a creative title',
- description: 'test',
- impact: 'This impacts only the UI',
- severity: Severity.LOW,
- reproduction: ''
- },
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
- title: 'This is a creative title',
- description: 'test',
- impact: 'This is impacts some things',
- severity: Severity.MEDIUM,
- reproduction: ''
- },
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
- title: 'This is a creative title',
- description: 'test',
- impact: 'This is impacts a lot',
- severity: Severity.HIGH,
- reproduction: ''
- },
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
- title: 'This is a creative title',
- description: 'test',
- impact: 'This is impacts a lot',
- severity: Severity.CRITICAL,
- reproduction: ''
- }
- ]);
- }
+ return this.http.get(`${this.apiBaseURL}/${pentestId}/findings`);
+ // return of([]);
+ /*Todo: Remove mocked Findings?
+ return of([
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
+ title: 'This is a creative title',
+ description: 'test',
+ impact: 'This impacts only the UI',
+ severity: Severity.LOW,
+ reproduction: ''
+ },
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
+ title: 'This is a creative title',
+ description: 'test',
+ impact: 'This is impacts some things',
+ severity: Severity.MEDIUM,
+ reproduction: ''
+ },
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
+ title: 'This is a creative title',
+ description: 'test',
+ impact: 'This is impacts a lot',
+ severity: Severity.HIGH,
+ reproduction: ''
+ },
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
+ title: 'This is a creative title',
+ description: 'test',
+ impact: 'This is impacts a lot',
+ severity: Severity.CRITICAL,
+ reproduction: ''
+ }
+ ]);*/
}
/**
@@ -141,26 +137,22 @@ export class PentestService {
* @param pentestId the id of the project
*/
public getCommentsByPentestId(pentestId: string): Observable {
- console.warn('Comments for:', pentestId);
- if (pentestId) {
- return this.http.get(`${this.apiBaseURL}/${pentestId}/comments`);
- } else {
- // return of([]);
- // Todo: Remove mocked Comments
- return of([
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd2',
- title: 'This is a creative title',
- description: 'This is a creative description',
- relatedFindings: ['ca96cc19-88ff-4874-8406-dc892620afd4'],
- },
- {
- id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
- title: 'This is a creative title',
- description: 'This is a creative description',
- relatedFindings: [],
- }
- ]);
- }
+ return this.http.get(`${this.apiBaseURL}/${pentestId}/comments`);
+ // return of([]);
+ /* ToDo: Use mocked Comments?
+ return of([
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd2',
+ title: 'This is a creative title',
+ description: 'This is a creative description',
+ relatedFindings: ['ca96cc19-88ff-4874-8406-dc892620afd4'],
+ },
+ {
+ id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
+ title: 'This is a creative title',
+ description: 'This is a creative description',
+ relatedFindings: [],
+ }
+ ]);*/
}
}
diff --git a/security-c4po-angular/src/shared/stores/project-state/project-state.actions.ts b/security-c4po-angular/src/shared/stores/project-state/project-state.actions.ts
index 3110836..d97a00d 100644
--- a/security-c4po-angular/src/shared/stores/project-state/project-state.actions.ts
+++ b/security-c4po-angular/src/shared/stores/project-state/project-state.actions.ts
@@ -33,3 +33,10 @@ export class ChangePentest {
constructor(public pentest: Pentest) {
}
}
+
+export class UpdatePentestFindings {
+ static readonly type = '[ProjectState] UpdatePentestFindings';
+
+ constructor(public findingId: string) {
+ }
+}
diff --git a/security-c4po-angular/src/shared/stores/project-state/project-state.ts b/security-c4po-angular/src/shared/stores/project-state/project-state.ts
index 2e0ef30..07be0d9 100644
--- a/security-c4po-angular/src/shared/stores/project-state/project-state.ts
+++ b/security-c4po-angular/src/shared/stores/project-state/project-state.ts
@@ -1,7 +1,13 @@
import {Action, Selector, State, StateContext} from '@ngxs/store';
import {Injectable} from '@angular/core';
import {Project} from '@shared/models/project.model';
-import {ChangeCategory, ChangePentest, ChangeProject, InitProjectState} from '@shared/stores/project-state/project-state.actions';
+import {
+ ChangeCategory,
+ ChangePentest,
+ ChangeProject,
+ InitProjectState,
+ UpdatePentestFindings
+} from '@shared/stores/project-state/project-state.actions';
import {Category} from '@shared/models/category.model';
import {Pentest} from '@shared/models/pentest.model';
@@ -80,4 +86,26 @@ export class ProjectState {
selectedPentest: {...pentest, projectId: state.selectedProject.id}
});
}
+
+ @Action(UpdatePentestFindings)
+ updatePentestFindings(ctx: StateContext, {findingId}: UpdatePentestFindings): void {
+ const state = ctx.getState();
+ let stateSelectedPentest: Pentest = state.selectedPentest;
+ const stateFindingIds: Array = stateSelectedPentest.findingIds || [];
+ let updatedFindingIds: Array = [];
+ if (!stateFindingIds.includes(findingId)) {
+ updatedFindingIds = [...stateFindingIds, findingId];
+ } else {
+ // ToDo: Add logic to remove findingId from array
+ }
+ // overwrites only findingIds
+ stateSelectedPentest = {
+ ...stateSelectedPentest,
+ findingIds: updatedFindingIds
+ };
+ // path project state
+ ctx.patchState({
+ selectedPentest: stateSelectedPentest
+ });
+ }
}
diff --git a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectController.kt b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectController.kt
index b0193f2..63015af 100644
--- a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectController.kt
+++ b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectController.kt
@@ -45,6 +45,7 @@ class ProjectController(private val projectService: ProjectService) {
@DeleteMapping("/{id}")
fun deleteProject(@PathVariable(value = "id") id: String): Mono> {
+ // ToDo: Delete all associated Pentests, Findings and Comments
return this.projectService.deleteProject(id).map{
ResponseEntity.ok().body(it.toProjectDeleteResponseBody())
}.switchIfEmpty {