feat: As a user I want to have an comments overview
This commit is contained in:
parent
747cade495
commit
5d89467c1e
|
@ -1 +1,83 @@
|
|||
<p>pentest-comments works!</p>
|
||||
<div class="comment-table">
|
||||
<table [nbTreeGrid]="dataSource">
|
||||
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||
<tr nbTreeGridRow *nbTreeGridRowDef="let comment; columns: columns"
|
||||
class="comment-cell"
|
||||
fragment="{{comment.data['commentId']}}">
|
||||
</tr>
|
||||
<!-- Comment ID -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.commentId' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
||||
{{ comment.data['commentId'] || '-' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.title' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
||||
{{ comment.data['title'] }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Description -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.description' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
||||
{{ comment.data['description'] }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Related Findings -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.relatedFindings' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment" class="related-finding-cell">
|
||||
{{ comment.data['relatedFindings'].length ? comment.data['relatedFindings'] : 'comment.no.relatedFindings' | translate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[4]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
size="small"
|
||||
shape="round"
|
||||
class="add-comment-button"
|
||||
(click)="onClickAddComment()">
|
||||
<fa-icon [icon]="fa.faPlus" class="new-comment-icon"></fa-icon>
|
||||
{{'comment.add' | translate}}
|
||||
</button>
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment" class="cell-actions">
|
||||
<div fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="1rem">
|
||||
<button nbButton
|
||||
status="primary"
|
||||
size="small"
|
||||
(click)="onClickEditComment(comment)">
|
||||
<fa-icon [icon]="fa.faPencilAlt"></fa-icon>
|
||||
</button>
|
||||
<button nbButton
|
||||
status="danger"
|
||||
size="small"
|
||||
(click)="onClickDeleteComment(comment)">
|
||||
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.length === 0 && loading$.getValue() === false" fxLayout="row" fxLayoutAlign="center center">
|
||||
<p class="error-text">
|
||||
{{'comment.no.comments' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
@import '../../../../assets/@theme/styles/themes';
|
||||
|
||||
.comment-table {
|
||||
// width: calc(78vw - 18%);
|
||||
width: 90vw;
|
||||
|
||||
.comment-cell {
|
||||
// Add style here
|
||||
}
|
||||
|
||||
.comment-cell:hover {
|
||||
// cursor: default;
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
|
||||
.related-finding-cell {
|
||||
// cursor: pointer;
|
||||
font-family: Courier, serif;
|
||||
color: nb-theme(color-info-default);
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
width: max-content;
|
||||
max-width: 200px;
|
||||
|
||||
.add-comment-button {
|
||||
.new-comment-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
padding-top: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -1,20 +1,92 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import { PentestCommentsComponent } from './pentest-comments.component';
|
||||
import {PentestCommentsComponent} from './pentest-comments.component';
|
||||
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 {NgxsModule, Store} from '@ngxs/store';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {NbButtonModule, NbTreeGridModule} from '@nebular/theme';
|
||||
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 {NotificationService} from '@shared/services/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/notification.service.mock';
|
||||
import {MockComponent} from 'ng-mocks';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
|
||||
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,
|
||||
findingsIds: [],
|
||||
commentsIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestCommentsComponent', () => {
|
||||
let component: PentestCommentsComponent;
|
||||
let fixture: ComponentFixture<PentestCommentsComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PentestCommentsComponent ]
|
||||
declarations: [
|
||||
PentestCommentsComponent,
|
||||
MockComponent(LoadingSpinnerComponent)
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
FontAwesomeModule,
|
||||
NbButtonModule,
|
||||
NbTreeGridModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestCommentsComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import {PentestService} from '@shared/services/pentest.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {filter, tap} from 'rxjs/operators';
|
||||
import {Comment, CommentEntry, transformCommentsToObjectiveEntries} from '@shared/models/comment.model';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-comments',
|
||||
templateUrl: './pentest-comments.component.html',
|
||||
|
@ -7,9 +18,80 @@ import { Component, OnInit } from '@angular/core';
|
|||
})
|
||||
export class PentestCommentsComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
@Input()
|
||||
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
|
||||
ngOnInit(): void {
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
// comments$: BehaviorSubject<Comment[]> = new BehaviorSubject<Comment[]>(null);
|
||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
columns: Array<CommentColumns> = [
|
||||
CommentColumns.COMMENT_ID, CommentColumns.TITLE, CommentColumns.DESCRIPTION, CommentColumns.RELATED_FINDINGS, CommentColumns.ACTIONS
|
||||
];
|
||||
dataSource: NbTreeGridDataSource<CommentEntry>;
|
||||
|
||||
data: CommentEntry[] = [];
|
||||
|
||||
getters: NbGetters<CommentEntry, CommentEntry> = {
|
||||
dataGetter: (node: CommentEntry) => node,
|
||||
childrenGetter: (node: CommentEntry) => node.childEntries || undefined,
|
||||
expandedGetter: (node: CommentEntry) => !!node.expanded,
|
||||
};
|
||||
|
||||
constructor(private readonly pentestService: PentestService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<CommentEntry>,
|
||||
private notificationService: NotificationService) {
|
||||
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadCommentsData();
|
||||
}
|
||||
|
||||
loadCommentsData(): void {
|
||||
this.pentestService.getCommentsByPentestId(this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '')
|
||||
.pipe(
|
||||
untilDestroyed(this),
|
||||
filter(isNotNullOrUndefined),
|
||||
tap(() => this.loading$.next(true))
|
||||
)
|
||||
.subscribe({
|
||||
next: (comments: Comment[]) => {
|
||||
this.data = transformCommentsToObjectiveEntries(comments);
|
||||
this.dataSource.setData(this.data, this.getters);
|
||||
this.loading$.next(false);
|
||||
},
|
||||
error: err => {
|
||||
console.log(err);
|
||||
this.notificationService.showPopup('comment.popup.not.found', PopupType.FAILURE);
|
||||
this.loading$.next(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickAddComment(): void {
|
||||
console.info('Coming soon..');
|
||||
}
|
||||
|
||||
onClickEditComment(comment): void {
|
||||
console.info('Coming soon..');
|
||||
}
|
||||
|
||||
onClickDeleteComment(comment): void {
|
||||
console.info('Coming soon..');
|
||||
}
|
||||
|
||||
// HTML only
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
}
|
||||
|
||||
enum CommentColumns {
|
||||
COMMENT_ID = 'commentId',
|
||||
TITLE = 'title',
|
||||
DESCRIPTION = 'description',
|
||||
RELATED_FINDINGS = 'relatedFindings',
|
||||
ACTIONS = 'actions'
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<app-pentest-findings [pentestInfo$] = pentest$></app-pentest-findings>
|
||||
</nb-tab>
|
||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.comments' | translate }}" badgeText="{{currentNumberOfComments$.getValue()}}" badgeStatus="info">
|
||||
<app-pentest-comments></app-pentest-comments>
|
||||
<app-pentest-comments [pentestInfo$] = pentest$></app-pentest-comments>
|
||||
</nb-tab>
|
||||
</nb-tabset>
|
||||
</div>
|
||||
|
|
|
@ -14,8 +14,17 @@
|
|||
{{ finding.data['findingId'] || '-' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Title -->
|
||||
<!-- Severity -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-severity">
|
||||
{{ 'finding.severity' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding" class="cell-severity" fxFill fxLayoutAlign="center none">
|
||||
<app-severity-tag [currentSeverity]="finding.data['severity']"></app-severity-tag>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.title' | translate }}
|
||||
</th>
|
||||
|
@ -24,7 +33,7 @@
|
|||
</td>
|
||||
</ng-container>
|
||||
<!-- Impact -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.impact' | translate }}
|
||||
</th>
|
||||
|
@ -32,15 +41,6 @@
|
|||
{{ finding.data['impact'] }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Severity -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.severity' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||
<app-severity-tag [currentSeverity]="finding.data['severity']"></app-severity-tag>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[4]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
|
||||
.cell-severity {
|
||||
width: 125px;
|
||||
max-width: 125px;
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
width: max-content;
|
||||
max-width: 180px;
|
||||
|
|
|
@ -3,11 +3,12 @@ import {PentestService} from '@shared/services/pentest.service';
|
|||
import {BehaviorSubject, Observable, of} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {tap} from 'rxjs/operators';
|
||||
import {filter, tap} from 'rxjs/operators';
|
||||
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||
import {Finding, FindingEntry, transformFindingsToObjectiveEntries} from '@shared/models/finding.model';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -26,7 +27,7 @@ export class PentestFindingsComponent implements OnInit {
|
|||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
columns: Array<FindingColumns> = [
|
||||
FindingColumns.FINDING_ID, FindingColumns.TITLE, FindingColumns.IMPACT, FindingColumns.SEVERITY, FindingColumns.ACTIONS
|
||||
FindingColumns.FINDING_ID, FindingColumns.SEVERITY, FindingColumns.TITLE, FindingColumns.IMPACT, FindingColumns.ACTIONS
|
||||
];
|
||||
dataSource: NbTreeGridDataSource<FindingEntry>;
|
||||
|
||||
|
@ -45,7 +46,6 @@ export class PentestFindingsComponent implements OnInit {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
console.warn('Selected Pentest: ', this.pentestInfo$.getValue());
|
||||
this.loadFindingsData();
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ export class PentestFindingsComponent implements OnInit {
|
|||
this.pentestService.getFindingsByPentestId(this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '')
|
||||
.pipe(
|
||||
untilDestroyed(this),
|
||||
filter(isNotNullOrUndefined),
|
||||
tap(() => this.loading$.next(true))
|
||||
)
|
||||
.subscribe({
|
||||
|
@ -89,8 +90,8 @@ export class PentestFindingsComponent implements OnInit {
|
|||
|
||||
enum FindingColumns {
|
||||
FINDING_ID = 'findingId',
|
||||
SEVERITY = 'severity',
|
||||
TITLE = 'title',
|
||||
IMPACT = 'impact',
|
||||
SEVERITY = 'severity',
|
||||
ACTIONS = 'actions'
|
||||
}
|
||||
|
|
|
@ -90,11 +90,20 @@
|
|||
},
|
||||
"finding": {
|
||||
"findingId": "Fund Id",
|
||||
"title": "Title",
|
||||
"title": "Titel",
|
||||
"impact": "Auswirkung",
|
||||
"severity": "Schwere",
|
||||
"add": "Fund hinzufügen",
|
||||
"no.findings": "Keine Funde verfügbar"
|
||||
"no.findings": "Keine Funde verfügbar",
|
||||
"popup": {
|
||||
"not.found": "Keine Funde gefunden",
|
||||
"save.success": "Fund erfolgreich gespeichert",
|
||||
"save.failed": "Fund konnte nicht gespeichert werden",
|
||||
"update.success": "Fund erfolgreich aktualisiert",
|
||||
"update.failed": "Fund konnte nicht aktualisiert werden",
|
||||
"delete.success": "Fund erfolgreich gelöscht",
|
||||
"delete.failed": "Fund konnte nicht gelöscht werden"
|
||||
}
|
||||
},
|
||||
"severities": {
|
||||
"low": "Niedrig",
|
||||
|
@ -102,6 +111,24 @@
|
|||
"high": "Hoch",
|
||||
"critical": "Kritisch"
|
||||
},
|
||||
"comment": {
|
||||
"commentId": "Kommentar Id",
|
||||
"title": "Titel",
|
||||
"description": "Beschreibung",
|
||||
"relatedFindings": "Verwandte Funde",
|
||||
"add": "Kommentar hinzufügen",
|
||||
"no.relatedFindings": "Nicht verbunden mit Fund",
|
||||
"no.comments": "Keine Kommentare verfügbar",
|
||||
"popup": {
|
||||
"not.found": "Keine Kommentare gefunden",
|
||||
"save.success": "Kommentar erfolgreich gespeichert",
|
||||
"save.failed": "Kommentar konnte nicht gespeichert werden",
|
||||
"update.success": "Kommentar erfolgreich aktualisiert",
|
||||
"update.failed": "Kommentar konnte nicht aktualisiert werden",
|
||||
"delete.success": "Kommentar erfolgreich gelöscht",
|
||||
"delete.failed": "Kommentar konnte nicht gelöscht werden"
|
||||
}
|
||||
},
|
||||
"pentest": {
|
||||
"testId": "Nr.",
|
||||
"title": "Titel",
|
||||
|
|
|
@ -90,11 +90,20 @@
|
|||
},
|
||||
"finding": {
|
||||
"findingId": "Finding Id",
|
||||
"severity": "Severity",
|
||||
"title": "Title",
|
||||
"impact": "Impact",
|
||||
"severity": "Severity",
|
||||
"add": "Add finding",
|
||||
"no.findings": "No findings available"
|
||||
"no.findings": "No findings available",
|
||||
"popup": {
|
||||
"not.found": "No finding found",
|
||||
"save.success": "Finding saved successfully",
|
||||
"save.failed": "Finding could not be saved",
|
||||
"update.success": "Finding updated successfully",
|
||||
"update.failed": "Finding could not be updated",
|
||||
"delete.success": "Finding deleted successfully",
|
||||
"delete.failed": "Finding could not be deleted"
|
||||
}
|
||||
},
|
||||
"severities": {
|
||||
"low": "Low",
|
||||
|
@ -102,6 +111,24 @@
|
|||
"high": "High",
|
||||
"critical": "Critical"
|
||||
},
|
||||
"comment": {
|
||||
"commentId": "Comment Id",
|
||||
"title": "Title",
|
||||
"description": "Description",
|
||||
"relatedFindings": "Related Findings",
|
||||
"add": "Add comment",
|
||||
"no.comments": "No comments available",
|
||||
"no.relatedFindings": "Not related to finding",
|
||||
"popup": {
|
||||
"not.found": "No comment found",
|
||||
"save.success": "Comment saved successfully",
|
||||
"save.failed": "Comment could not be saved",
|
||||
"update.success": "Comment updated successfully",
|
||||
"update.failed": "Comment could not be updated",
|
||||
"delete.success": "Comment deleted successfully",
|
||||
"delete.failed": "Comment could not be deleted"
|
||||
}
|
||||
},
|
||||
"pentest": {
|
||||
"testId": "No.",
|
||||
"title": "Title",
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import {v4 as UUID} from 'uuid';
|
||||
import {Severity} from '@shared/models/severity.enum';
|
||||
|
||||
export class Comment {
|
||||
id?: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
relatedFindings?: Array<string>;
|
||||
|
||||
constructor(title: string,
|
||||
description: string,
|
||||
id?: string,
|
||||
relatedFindings?: Array<string>) {
|
||||
this.id = id ? id : UUID();
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.relatedFindings = relatedFindings;
|
||||
}
|
||||
}
|
||||
|
||||
export interface CommentEntry {
|
||||
commentId: string;
|
||||
title: string;
|
||||
description: string;
|
||||
relatedFindings: Array<string>;
|
||||
kind?: string;
|
||||
childEntries?: [];
|
||||
expanded?: boolean;
|
||||
}
|
||||
|
||||
export function transformCommentsToObjectiveEntries(findings: Comment[]): CommentEntry[] {
|
||||
const findingEntries: CommentEntry[] = [];
|
||||
findings.forEach((value: Comment) => {
|
||||
findingEntries.push({
|
||||
commentId: value.id,
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
relatedFindings: value.relatedFindings,
|
||||
kind: 'cell',
|
||||
childEntries: null,
|
||||
expanded: false
|
||||
} as CommentEntry);
|
||||
});
|
||||
return findingEntries;
|
||||
}
|
|
@ -3,27 +3,27 @@ import {Severity} from '@shared/models/severity.enum';
|
|||
|
||||
export class Finding {
|
||||
id?: string;
|
||||
severity: Severity;
|
||||
title: string;
|
||||
description?: string;
|
||||
impact: string;
|
||||
severity: Severity;
|
||||
affectedUrls?: Array<string>;
|
||||
reproduction?: string;
|
||||
mitigation?: string;
|
||||
|
||||
constructor(title: string,
|
||||
severity: Severity,
|
||||
description: string,
|
||||
impact: string,
|
||||
severity: Severity,
|
||||
reproduction: string,
|
||||
id?: string,
|
||||
affectedUrls?: Array<string>,
|
||||
mitigation?: string) {
|
||||
this.id = id ? id : UUID();
|
||||
this.severity = severity;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.impact = impact;
|
||||
this.severity = severity;
|
||||
this.affectedUrls = affectedUrls ? affectedUrls : null;
|
||||
this.reproduction = reproduction;
|
||||
this.mitigation = mitigation ? mitigation : null;
|
||||
|
@ -32,9 +32,9 @@ export class Finding {
|
|||
|
||||
export interface FindingEntry {
|
||||
findingId: string;
|
||||
severity: Severity;
|
||||
title: string;
|
||||
impact: string;
|
||||
severity: Severity;
|
||||
kind?: string;
|
||||
childEntries?: [];
|
||||
expanded?: boolean;
|
||||
|
@ -45,9 +45,9 @@ export function transformFindingsToObjectiveEntries(findings: Finding[]): Findin
|
|||
findings.forEach((value: Finding) => {
|
||||
findingEntries.push({
|
||||
findingId: value.id,
|
||||
severity: value.severity,
|
||||
title: value.title,
|
||||
impact: value.impact,
|
||||
severity: value.severity,
|
||||
kind: 'cell',
|
||||
childEntries: null,
|
||||
expanded: false
|
||||
|
|
|
@ -10,6 +10,7 @@ import {catchError, map, switchMap} from 'rxjs/operators';
|
|||
import {getTempPentestsForCategory} from '@shared/functions/categories/get-temp-pentests-for-category.function';
|
||||
import {Finding} from '@shared/models/finding.model';
|
||||
import {Severity} from '@shared/models/severity.enum';
|
||||
import {Comment} from '@shared/models/comment.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -92,4 +93,32 @@ export class PentestService {
|
|||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Comments for Pentest Id
|
||||
* @param pentestId the id of the project
|
||||
*/
|
||||
public getCommentsByPentestId(pentestId: string): Observable<Comment[]> {
|
||||
console.warn('Comments for:', pentestId);
|
||||
if (pentestId) {
|
||||
return this.http.get<Comment[]>(`${this.apiBaseURL}/${pentestId}/comments`);
|
||||
} else {
|
||||
// return of([]);
|
||||
// Todo: Remove mocked Comments
|
||||
return of([
|
||||
{
|
||||
id: 'ca96cc19-88ff-4874-8406-dc892620afd2',
|
||||
title: 'This is a lit test finding ma brother',
|
||||
description: 'fucked up a lot man. better fix it',
|
||||
relatedFindings: ['ca96cc19-88ff-4874-8406-dc892620afd4'],
|
||||
},
|
||||
{
|
||||
id: 'ca96cc19-88ff-4874-8406-dc892620afd4',
|
||||
title: 'This is a lit test finding ma brother',
|
||||
description: 'fucked up a lot man. better fix it',
|
||||
relatedFindings: [],
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package comment
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed
|
||||
import java.util.*
|
||||
|
||||
data class Comment (
|
||||
@Indexed(background = true, unique = true)
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val title: String,
|
||||
val description: String,
|
||||
val relatedFindings: List<String>? = emptyList()
|
||||
)
|
|
@ -0,0 +1,18 @@
|
|||
package comment
|
||||
|
||||
import com.securityc4po.api.BaseEntity
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
|
||||
@Document(collection = "comments")
|
||||
open class CommentEntity(
|
||||
data: Comment
|
||||
) : BaseEntity<Comment>(data)
|
||||
|
||||
fun CommentEntity.toComment(): Comment {
|
||||
return Comment(
|
||||
this.data.id,
|
||||
this.data.title,
|
||||
this.data.description,
|
||||
this.data.relatedFindings
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.securityc4po.api.pentest
|
||||
package finding
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed
|
||||
import java.util.*
|
||||
|
@ -6,10 +6,10 @@ import java.util.*
|
|||
data class Finding (
|
||||
@Indexed(background = true, unique = true)
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val severity: Severity,
|
||||
val title: String,
|
||||
val description: String,
|
||||
val impact: String,
|
||||
val severity: Severity,
|
||||
val affectedUrls: List<String>? = emptyList(),
|
||||
val reproduction: String,
|
||||
val mitigation: String
|
|
@ -0,0 +1,23 @@
|
|||
package finding
|
||||
|
||||
import com.securityc4po.api.BaseEntity
|
||||
import comment.Comment
|
||||
import org.springframework.data.mongodb.core.mapping.Document
|
||||
|
||||
@Document(collection = "findings")
|
||||
open class FindingEntity(
|
||||
data: Finding
|
||||
) : BaseEntity<Finding>(data)
|
||||
|
||||
fun FindingEntity.toFinding(): Finding {
|
||||
return finding.Finding(
|
||||
this.data.id,
|
||||
this.data.severity,
|
||||
this.data.title,
|
||||
this.data.description,
|
||||
this.data.impact,
|
||||
this.data.affectedUrls,
|
||||
this.data.reproduction,
|
||||
this.data.mitigation
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.securityc4po.api.pentest
|
||||
package finding
|
||||
|
||||
enum class Severity {
|
||||
LOW,
|
Loading…
Reference in New Issue