Compare commits
1 Commits
main
...
c4po_mhg_8
Author | SHA1 | Date |
---|---|---|
|
7114f129cf |
|
@ -36,6 +36,7 @@ import {ProjectState} from '@shared/stores/project-state/project-state';
|
|||
import {CustomOverlayContainer} from '@shared/modules/custom-overlay-container.component';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {RetryDialogModule} from '@shared/modules/retry-dialog/retry-dialog.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -72,6 +73,7 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
|||
}),
|
||||
HeaderModule,
|
||||
HomeModule,
|
||||
RetryDialogModule
|
||||
],
|
||||
providers: [
|
||||
HttpClient,
|
||||
|
|
|
@ -5,13 +5,11 @@ import * as FA from '@fortawesome/free-solid-svg-icons';
|
|||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||
import {filter, tap} from 'rxjs/operators';
|
||||
import {
|
||||
Comment,
|
||||
CommentDialogBody,
|
||||
CommentEntry,
|
||||
transformCommentsToObjectiveEntries,
|
||||
transformCommentToRequestBody
|
||||
transformCommentsToObjectiveEntries
|
||||
} from '@shared/models/comment.model';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
|
@ -115,25 +113,13 @@ export class PentestCommentsComponent implements OnInit {
|
|||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: CommentDialogBody) =>
|
||||
this.commentService.saveComment(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
transformCommentToRequestBody(value)
|
||||
)
|
||||
),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newComment: Comment) => {
|
||||
this.store.dispatch(new UpdatePentestComments(newComment.id));
|
||||
this.loadCommentsData();
|
||||
this.notificationService.showPopup('comment.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.notificationService.showPopup('comment.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -154,24 +140,13 @@ export class PentestCommentsComponent implements OnInit {
|
|||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: CommentDialogBody) =>
|
||||
this.commentService.updateComment(
|
||||
commentEntry.data.commentId,
|
||||
transformCommentToRequestBody(value)
|
||||
)
|
||||
),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (updatedComment: Comment) => {
|
||||
this.loadCommentsData();
|
||||
this.notificationService.showPopup('comment.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.notificationService.showPopup('comment.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -206,23 +181,10 @@ export class PentestCommentsComponent implements OnInit {
|
|||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
switchMap(() => this.commentService.deleteCommentByPentestAndCommentId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
commentEntry.data.commentId)
|
||||
),
|
||||
catchError(() => {
|
||||
this.notificationService.showPopup('comment.popup.delete.failed', PopupType.FAILURE);
|
||||
return [];
|
||||
}),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedComment: any) => {
|
||||
this.store.dispatch(new UpdatePentestComments(deletedComment.id));
|
||||
this.loadCommentsData();
|
||||
this.notificationService.showPopup('comment.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
next: () => {
|
||||
this.deleteComment(commentEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -231,6 +193,37 @@ export class PentestCommentsComponent implements OnInit {
|
|||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
private deleteComment(commentEntry): void {
|
||||
this.commentService.deleteCommentByPentestAndCommentId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
commentEntry.data.commentId)
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedComment: any) => {
|
||||
this.store.dispatch(new UpdatePentestComments(deletedComment.id));
|
||||
this.loadCommentsData();
|
||||
this.notificationService.showPopup('comment.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.onRequestFailed(commentEntry);
|
||||
this.notificationService.showPopup('comment.popup.delete.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.deleteComment(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum CommentColumns {
|
||||
|
|
|
@ -2,14 +2,12 @@ import {Component, OnInit} from '@angular/core';
|
|||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||
import { filter, tap} from 'rxjs/operators';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {
|
||||
Finding,
|
||||
FindingDialogBody,
|
||||
FindingEntry,
|
||||
transformFindingsToObjectiveEntries,
|
||||
transformFindingToRequestBody,
|
||||
} from '@shared/models/finding.model';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
|
@ -31,9 +29,9 @@ import {FindingService} from '@shared/services/api/finding.service';
|
|||
})
|
||||
export class PentestFindingsComponent implements OnInit {
|
||||
|
||||
constructor(private readonly findingService: FindingService,
|
||||
constructor(private findingService: FindingService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<FindingEntry>,
|
||||
private notificationService: NotificationService,
|
||||
private readonly notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private findingDialogService: FindingDialogService,
|
||||
private store: Store) {
|
||||
|
@ -111,26 +109,13 @@ export class PentestFindingsComponent implements OnInit {
|
|||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
/*tap((value) => console.warn('FindingDialogBody: ', value)),*/
|
||||
mergeMap((value: FindingDialogBody) =>
|
||||
this.findingService.saveFinding(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
transformFindingToRequestBody(value)
|
||||
)
|
||||
),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newFinding: Finding) => {
|
||||
this.store.dispatch(new UpdatePentestFindings(newFinding.id));
|
||||
this.loadFindingsData();
|
||||
this.notificationService.showPopup('finding.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.notificationService.showPopup('finding.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -150,25 +135,13 @@ export class PentestFindingsComponent implements OnInit {
|
|||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
/*tap((value) => console.warn('FindingDialogBody: ', value)),*/
|
||||
mergeMap((value: FindingDialogBody) =>
|
||||
this.findingService.updateFinding(
|
||||
findingEntry.data.findingId,
|
||||
transformFindingToRequestBody(value)
|
||||
)
|
||||
),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (updatedFinding: Finding) => {
|
||||
this.loadFindingsData();
|
||||
this.notificationService.showPopup('finding.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.notificationService.showPopup('finding.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -190,23 +163,10 @@ export class PentestFindingsComponent implements OnInit {
|
|||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
switchMap(() => this.findingService.deleteFindingByPentestAndFindingId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
findingEntry.data.findingId)
|
||||
),
|
||||
catchError(() => {
|
||||
this.notificationService.showPopup('finding.popup.delete.failed', PopupType.FAILURE);
|
||||
return [];
|
||||
}),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedFinding: any) => {
|
||||
this.store.dispatch(new UpdatePentestFindings(deletedFinding.id));
|
||||
this.loadFindingsData();
|
||||
this.notificationService.showPopup('finding.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
next: () => {
|
||||
this.deleteFinding(findingEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -214,6 +174,37 @@ export class PentestFindingsComponent implements OnInit {
|
|||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
private deleteFinding(findingEntry): void {
|
||||
this.findingService.deleteFindingByPentestAndFindingId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
findingEntry.data.findingId)
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedFinding: any) => {
|
||||
this.store.dispatch(new UpdatePentestFindings(deletedFinding.id));
|
||||
this.loadFindingsData();
|
||||
this.notificationService.showPopup('finding.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.onRequestFailed(findingEntry);
|
||||
this.notificationService.showPopup('finding.popup.delete.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.deleteFinding(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum FindingColumns {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {Project, ProjectDialogBody} from '@shared/models/project.model';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||
import {filter, tap} from 'rxjs/operators';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
|
@ -70,17 +70,10 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: ProjectDialogBody) => this.projectService.saveProject(value)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.notificationService.showPopup('project.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -96,17 +89,10 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: ProjectDialogBody) => this.projectService.updateProject(project.id, value)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -124,18 +110,10 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
message
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
switchMap(() => this.projectService.deleteProjectById(project.id)),
|
||||
catchError(() => {
|
||||
this.notificationService.showPopup('project.popup.delete.failed', PopupType.FAILURE);
|
||||
return [];
|
||||
}),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.deleteProject(project);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -152,18 +130,10 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
secMessage
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
switchMap(() => this.projectService.deleteProjectById(project.id)),
|
||||
catchError(() => {
|
||||
this.notificationService.showPopup('project.popup.delete.failed', PopupType.FAILURE);
|
||||
return [];
|
||||
}),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.deleteProject(project);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -185,4 +155,31 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
private deleteProject(project: Project): void {
|
||||
this.projectService.deleteProjectById(project.id).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
this.notificationService.showPopup('project.popup.delete.failed', PopupType.FAILURE);
|
||||
this.onRequestFailed(project);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.deleteProject(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,14 @@
|
|||
"username": "Nutzername",
|
||||
"password": "Passwort",
|
||||
"no.progress": "Kein Fortschritt",
|
||||
"project": "Projekt",
|
||||
"validationMessage": {
|
||||
"inputNotMatching": "Eingabe stimmt nicht überein!"
|
||||
},
|
||||
"project": "Projekt"
|
||||
"retry.dialog": {
|
||||
"title": "Etwas ist schief gelaufen...",
|
||||
"information": "Fehler beim verarbeiten Ihrer Anfrage. \nBitte versuchen Sie es erneut oder zu einem späteren Zeitpunkt."
|
||||
}
|
||||
},
|
||||
"languageKeys":{
|
||||
"de-DE": "Deutsch",
|
||||
|
|
|
@ -21,10 +21,14 @@
|
|||
"username": "Username",
|
||||
"password": "Password",
|
||||
"no.progress": "No progress",
|
||||
"project": "Project",
|
||||
"validationMessage": {
|
||||
"inputNotMatching": "Input does not match!"
|
||||
},
|
||||
"project": "Project"
|
||||
"retry.dialog": {
|
||||
"title": "Something went wrong...",
|
||||
"information": "An error occured while processing your request. \nPlease retry or try it again later."
|
||||
}
|
||||
},
|
||||
"languageKeys":{
|
||||
"de-DE": "German",
|
||||
|
|
|
@ -4,7 +4,13 @@ import {GenericDialogData, GenericFormFieldConfig} from '@shared/models/generic-
|
|||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import deepEqual from 'deep-equal';
|
||||
import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme';
|
||||
import {UntilDestroy} from '@ngneat/until-destroy';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Comment, transformCommentToRequestBody} from '@shared/models/comment.model';
|
||||
import {UpdatePentestComments} from '@shared/stores/project-state/project-state.actions';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {CommentService} from '@shared/services/api/comment.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-comment-dialog',
|
||||
|
@ -26,7 +32,11 @@ export class CommentDialogComponent implements OnInit {
|
|||
constructor(
|
||||
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
|
||||
private fb: FormBuilder,
|
||||
protected dialogRef: NbDialogRef<CommentDialogComponent>
|
||||
protected dialogRef: NbDialogRef<CommentDialogComponent>,
|
||||
private commentService: CommentService,
|
||||
private readonly notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private store: Store
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -50,11 +60,13 @@ export class CommentDialogComponent implements OnInit {
|
|||
}
|
||||
|
||||
onClickSave(value: any): void {
|
||||
this.dialogRef.close({
|
||||
title: value.commentTitle,
|
||||
description: value.commentDescription,
|
||||
// relatedFindings: this.selectedFindings ? this.selectedFindings : []
|
||||
});
|
||||
if (this.dialogData.options[0].headerLabelKey.includes('create')) {
|
||||
// Save
|
||||
this.saveComment(value);
|
||||
} else {
|
||||
// Update
|
||||
this.updateComment(value);
|
||||
}
|
||||
}
|
||||
|
||||
onClickClose(): void {
|
||||
|
@ -91,4 +103,67 @@ export class CommentDialogComponent implements OnInit {
|
|||
});
|
||||
return commentData;
|
||||
}
|
||||
|
||||
saveComment(value): void {
|
||||
const dialogRes = {
|
||||
title: value.commentTitle,
|
||||
description: value.commentDescription,
|
||||
// relatedFindings: this.selectedFindings ? this.selectedFindings : []
|
||||
};
|
||||
|
||||
this.commentService.saveComment(
|
||||
this.dialogData.options[0].additionalData.id,
|
||||
transformCommentToRequestBody(dialogRes)
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newComment: Comment) => {
|
||||
this.store.dispatch(new UpdatePentestComments(newComment.id));
|
||||
this.dialogRef.close();
|
||||
this.notificationService.showPopup('comment.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('comment.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateComment(value): void {
|
||||
const dialogRes = {
|
||||
title: value.commentTitle,
|
||||
description: value.commentDescription,
|
||||
// relatedFindings: this.selectedFindings ? this.selectedFindings : []
|
||||
};
|
||||
|
||||
this.commentService.updateComment(
|
||||
this.dialogData.options[0].additionalData.id,
|
||||
transformCommentToRequestBody(dialogRes)
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (updatedComment: Comment) => {
|
||||
this.dialogRef.close();
|
||||
this.notificationService.showPopup('comment.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('comment.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.onClickSave(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {Observable} from 'rxjs';
|
|||
import {Validators} from '@angular/forms';
|
||||
import {CommentDialogComponent} from '@shared/modules/comment-dialog/comment-dialog.component';
|
||||
import {Comment} from '@shared/models/comment.model';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
|
||||
@Injectable()
|
||||
export class CommentDialogService {
|
||||
|
@ -31,16 +32,18 @@ export class CommentDialogService {
|
|||
public openCommentDialog(componentOrTemplateRef: ComponentType<any>,
|
||||
findingIds: string[],
|
||||
comment?: Comment,
|
||||
config?: Partial<NbDialogConfig<Partial<any> | string>>): Observable<any> {
|
||||
config?: Partial<NbDialogConfig<Partial<any> | string>>,
|
||||
pentestInfo?: Pentest): Observable<any> {
|
||||
let dialogOptions: Partial<NbDialogConfig<Partial<any> | string>>;
|
||||
let dialogData: GenericDialogData;
|
||||
// Preselect attachments
|
||||
const attachments: string[] = [];
|
||||
/* ToDo: Use after file upload is implemented
|
||||
if (comment && comment.attachments.length > 0) {
|
||||
comment.attachments.forEach(attachment => {
|
||||
// Load attachment to show
|
||||
});
|
||||
}
|
||||
}*/
|
||||
// Setup CommentDialogBody
|
||||
dialogData = {
|
||||
form: {
|
||||
|
@ -78,7 +81,8 @@ export class CommentDialogService {
|
|||
{
|
||||
headerLabelKey: 'comment.edit.header',
|
||||
buttonKey: 'global.action.update',
|
||||
accentColor: 'warning'
|
||||
accentColor: 'warning',
|
||||
additionalData: comment
|
||||
},
|
||||
];
|
||||
} else {
|
||||
|
@ -86,7 +90,8 @@ export class CommentDialogService {
|
|||
{
|
||||
headerLabelKey: 'comment.create.header',
|
||||
buttonKey: 'global.action.save',
|
||||
accentColor: 'info'
|
||||
accentColor: 'info',
|
||||
additionalData: pentestInfo
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import {shareReplay, tap} from 'rxjs/operators';
|
|||
import {downloadFile} from '@shared/functions/download-file.function';
|
||||
import {Loading, LoadingState} from '@shared/models/loading.model';
|
||||
import {HttpEvent, HttpEventType} from '@angular/common/http';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-export-report-dialog',
|
||||
|
@ -28,7 +29,8 @@ export class ExportReportDialogComponent implements OnInit {
|
|||
private projectService: ProjectService,
|
||||
private reportingService: ReportingService,
|
||||
private readonly notificationService: NotificationService,
|
||||
protected dialogRef: NbDialogRef<ExportReportDialogComponent>
|
||||
protected dialogRef: NbDialogRef<ExportReportDialogComponent>,
|
||||
private dialogService: DialogService
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -105,6 +107,7 @@ export class ExportReportDialogComponent implements OnInit {
|
|||
error: error => {
|
||||
console.error(error);
|
||||
this.loading$.next(false);
|
||||
this.onRequestFailed(reportFormat, reportLanguage);
|
||||
this.notificationService.showPopup('report.popup.generation.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
|
@ -136,6 +139,19 @@ export class ExportReportDialogComponent implements OnInit {
|
|||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
onRequestFailed(reportFormat: string, reportLanguage: string): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
// ToDo: Send same request again
|
||||
this.onClickExport(reportFormat, reportLanguage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export enum ExportFormatOptions {
|
||||
|
|
|
@ -3,9 +3,15 @@ import {FormBuilder, FormGroup} from '@angular/forms';
|
|||
import {GenericDialogData, GenericFormFieldConfig} from '@shared/models/generic-dialog-data';
|
||||
import {NB_DIALOG_CONFIG, NbDialogRef, NbTagComponent} from '@nebular/theme';
|
||||
import deepEqual from 'deep-equal';
|
||||
import {UntilDestroy} from '@ngneat/until-destroy';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Severity} from '@shared/models/severity.enum';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {Finding, transformFindingToRequestBody} from '@shared/models/finding.model';
|
||||
import {FindingService} from '@shared/services/api/finding.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {UpdatePentestFindings} from '@shared/stores/project-state/project-state.actions';
|
||||
import {Store} from '@ngxs/store';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -38,7 +44,11 @@ export class FindingDialogComponent implements OnInit {
|
|||
constructor(
|
||||
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
|
||||
private fb: FormBuilder,
|
||||
protected dialogRef: NbDialogRef<FindingDialogComponent>
|
||||
protected dialogRef: NbDialogRef<FindingDialogComponent>,
|
||||
private findingService: FindingService,
|
||||
private readonly notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private store: Store
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -64,18 +74,6 @@ export class FindingDialogComponent implements OnInit {
|
|||
return this.fb.group(config);
|
||||
}
|
||||
|
||||
onClickSave(value: any): void {
|
||||
this.dialogRef.close({
|
||||
title: value.findingTitle,
|
||||
severity: this.formArray[1].controlsConfig[0].value,
|
||||
description: value.findingDescription,
|
||||
impact: value.findingImpact,
|
||||
affectedUrls: this.affectedUrls ? this.affectedUrls : [],
|
||||
reproduction: value.findingReproduction,
|
||||
mitigation: value.findingMitigation
|
||||
});
|
||||
}
|
||||
|
||||
renderAffectedUrls(affectedUrls: string[]): void {
|
||||
affectedUrls.forEach(url => this.initialAffectedUrls.push(url));
|
||||
affectedUrls.forEach(url => this.affectedUrls.push(url));
|
||||
|
@ -95,6 +93,16 @@ export class FindingDialogComponent implements OnInit {
|
|||
this.affectedUrls = this.affectedUrls.filter(t => t !== tagToRemove.text);
|
||||
}
|
||||
|
||||
onClickSave(value: any): void {
|
||||
if (this.dialogData.options[0].headerLabelKey.includes('create')) {
|
||||
// Save
|
||||
this.saveFinding(value);
|
||||
} else {
|
||||
// Update
|
||||
this.updateFinding(value);
|
||||
}
|
||||
}
|
||||
|
||||
onClickClose(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
@ -168,6 +176,77 @@ export class FindingDialogComponent implements OnInit {
|
|||
});
|
||||
return findingData;
|
||||
}
|
||||
|
||||
private saveFinding(value): void {
|
||||
const dialogRes = {
|
||||
title: value.findingTitle,
|
||||
severity: this.formArray[1].controlsConfig[0].value,
|
||||
description: value.findingDescription,
|
||||
impact: value.findingImpact,
|
||||
affectedUrls: this.affectedUrls ? this.affectedUrls : [],
|
||||
reproduction: value.findingReproduction,
|
||||
mitigation: value.findingMitigation
|
||||
};
|
||||
|
||||
this.findingService.saveFinding(
|
||||
this.dialogData.options[0].additionalData.id,
|
||||
transformFindingToRequestBody(dialogRes)
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newFinding: Finding) => {
|
||||
this.store.dispatch(new UpdatePentestFindings(newFinding.id));
|
||||
this.dialogRef.close();
|
||||
this.notificationService.showPopup('finding.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('finding.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateFinding(value): void {
|
||||
const dialogRes = {
|
||||
title: value.findingTitle,
|
||||
severity: this.formArray[1].controlsConfig[0].value,
|
||||
description: value.findingDescription,
|
||||
impact: value.findingImpact,
|
||||
affectedUrls: this.affectedUrls ? this.affectedUrls : [],
|
||||
reproduction: value.findingReproduction,
|
||||
mitigation: value.findingMitigation
|
||||
};
|
||||
|
||||
this.findingService.updateFinding(
|
||||
this.dialogData.options[0].additionalData.id,
|
||||
transformFindingToRequestBody(dialogRes)
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newFinding: Finding) => {
|
||||
this.dialogRef.close();
|
||||
this.notificationService.showPopup('finding.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('finding.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.onClickSave(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface SeverityText {
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Validators} from '@angular/forms';
|
|||
import {FindingDialogComponent} from '@shared/modules/finding-dialog/finding-dialog.component';
|
||||
import {Finding} from '@shared/models/finding.model';
|
||||
import {Severity} from '@shared/models/severity.enum';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
|
||||
@Injectable()
|
||||
export class FindingDialogService {
|
||||
|
@ -31,7 +32,8 @@ export class FindingDialogService {
|
|||
|
||||
public openFindingDialog(componentOrTemplateRef: ComponentType<any>,
|
||||
finding?: Finding,
|
||||
config?: Partial<NbDialogConfig<Partial<any> | string>>): Observable<any> {
|
||||
config?: Partial<NbDialogConfig<Partial<any> | string>>,
|
||||
pentestInfo?: Pentest): Observable<any> {
|
||||
let dialogOptions: Partial<NbDialogConfig<Partial<any> | string>>;
|
||||
let dialogData: GenericDialogData;
|
||||
let severity;
|
||||
|
@ -141,7 +143,8 @@ export class FindingDialogService {
|
|||
{
|
||||
headerLabelKey: 'finding.edit.header',
|
||||
buttonKey: 'global.action.update',
|
||||
accentColor: 'warning'
|
||||
accentColor: 'warning',
|
||||
additionalData: finding
|
||||
},
|
||||
];
|
||||
} else {
|
||||
|
@ -149,7 +152,8 @@ export class FindingDialogService {
|
|||
{
|
||||
headerLabelKey: 'finding.create.header',
|
||||
buttonKey: 'global.action.save',
|
||||
accentColor: 'info'
|
||||
accentColor: 'info',
|
||||
additionalData: pentestInfo
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@ import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme';
|
|||
import {FormBuilder, FormGroup} from '@angular/forms';
|
||||
import {GenericFormFieldConfig, GenericDialogData} from '@shared/models/generic-dialog-data';
|
||||
import deepEqual from 'deep-equal';
|
||||
import {UntilDestroy} from '@ngneat/until-destroy';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -21,6 +24,9 @@ export class ProjectDialogComponent implements OnInit {
|
|||
constructor(
|
||||
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
|
||||
private fb: FormBuilder,
|
||||
private dialogService: DialogService,
|
||||
private projectService: ProjectService,
|
||||
private readonly notificationService: NotificationService,
|
||||
protected dialogRef: NbDialogRef<ProjectDialogComponent>
|
||||
) {
|
||||
}
|
||||
|
@ -40,12 +46,13 @@ export class ProjectDialogComponent implements OnInit {
|
|||
}
|
||||
|
||||
onClickSave(value): void {
|
||||
this.dialogRef.close({
|
||||
title: value.projectTitle,
|
||||
client: value.projectClient,
|
||||
tester: value.projectTester,
|
||||
summary: value.projectSummary
|
||||
});
|
||||
if (this.dialogData.options[0].headerLabelKey.includes('create')) {
|
||||
// Save
|
||||
this.saveProject(value);
|
||||
} else {
|
||||
// Update
|
||||
this.updateProject(value);
|
||||
}
|
||||
}
|
||||
|
||||
onClickClose(): void {
|
||||
|
@ -85,4 +92,64 @@ export class ProjectDialogComponent implements OnInit {
|
|||
});
|
||||
return projectData;
|
||||
}
|
||||
|
||||
private saveProject(value): void {
|
||||
const dialogRes = {
|
||||
title: value.projectTitle,
|
||||
client: value.projectClient,
|
||||
tester: value.projectTester,
|
||||
summary: value.projectSummary
|
||||
};
|
||||
this.projectService.saveProject(dialogRes).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe(
|
||||
{
|
||||
next: () => {
|
||||
this.notificationService.showPopup('project.popup.save.success', PopupType.SUCCESS);
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('project.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private updateProject(value): void {
|
||||
const dialogRes = {
|
||||
title: value.projectTitle,
|
||||
client: value.projectClient,
|
||||
tester: value.projectTester,
|
||||
summary: value.projectSummary
|
||||
};
|
||||
this.projectService.updateProject(this.dialogData.options[0].additionalData.id, dialogRes).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe(
|
||||
{
|
||||
next: () => {
|
||||
this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS);
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
this.onRequestFailed(value);
|
||||
this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.onClickSave(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ export class ProjectDialogService {
|
|||
{
|
||||
headerLabelKey: 'project.edit.header',
|
||||
buttonKey: 'global.action.update',
|
||||
accentColor: 'warning'
|
||||
accentColor: 'warning',
|
||||
additionalData: project
|
||||
},
|
||||
];
|
||||
} else {
|
||||
|
@ -104,7 +105,8 @@ export class ProjectDialogService {
|
|||
{
|
||||
headerLabelKey: 'project.create.header',
|
||||
buttonKey: 'global.action.save',
|
||||
accentColor: 'info'
|
||||
accentColor: 'info',
|
||||
additionalData: project
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<nb-card accent="danger">
|
||||
<nb-card-header fxLayoutAlign="start center" class="dialog-header confirm">
|
||||
{{ 'global.retry.dialog.title' | translate }}
|
||||
</nb-card-header>
|
||||
<nb-card-body class="dialog-body">
|
||||
{{ 'global.retry.dialog.information' | translate }}
|
||||
</nb-card-body>
|
||||
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
||||
<button nbButton size="small"
|
||||
class="retry-dialog-button"
|
||||
status="danger"
|
||||
(click)="onClickRetry()">
|
||||
<fa-icon [icon]="fa.faRedoAlt" class="dialog-button-icon"></fa-icon>
|
||||
{{ 'global.action.retry' | translate }}
|
||||
</button>
|
||||
<button nbButton size="small"
|
||||
class="cancel-dialog-button"
|
||||
(click)="onClickCancel()">
|
||||
{{ 'global.action.cancel' | translate }}
|
||||
</button>
|
||||
</nb-card-footer>
|
||||
</nb-card>
|
|
@ -0,0 +1,11 @@
|
|||
@import "../../../assets/@theme/styles/_dialog.scss";
|
||||
|
||||
* {
|
||||
}
|
||||
|
||||
.retry-dialog-button {
|
||||
// margin: 6rem 2rem 6rem 0;
|
||||
.dialog-button-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {RetryDialogComponent} from './retry-dialog.component';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NbButtonModule, NbCardModule, NbDialogRef, NbLayoutModule, NbStatusService} from '@nebular/theme';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {MockProvider} from 'ng-mocks';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
|
||||
describe('RetryDialogComponent', () => {
|
||||
let component: RetryDialogComponent;
|
||||
let fixture: ComponentFixture<RetryDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
RetryDialogComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
FlexLayoutModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
HttpClientModule,
|
||||
HttpClientTestingModule
|
||||
],
|
||||
providers: [
|
||||
MockProvider(NbStatusService),
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NbDialogRef, useValue: {}}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RetryDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import {Component, Input} from '@angular/core';
|
||||
import {NbDialogRef} from '@nebular/theme';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-retry-dialog',
|
||||
templateUrl: './retry-dialog.component.html',
|
||||
styleUrls: ['./retry-dialog.component.scss']
|
||||
})
|
||||
export class RetryDialogComponent {
|
||||
/**
|
||||
* @param data contains all relevant information the dialog needs
|
||||
* @param data.title The translation key for the dialog title
|
||||
* @param data.key The translation key for the shown message
|
||||
* @param data.data The data that may be used in the message translation key
|
||||
*/
|
||||
@Input() data: any;
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
|
||||
constructor(protected dialogRef: NbDialogRef<any>) {
|
||||
}
|
||||
|
||||
onClickRetry(): void {
|
||||
this.dialogRef.close({retry: true});
|
||||
}
|
||||
|
||||
onClickCancel(): void {
|
||||
this.dialogRef.close({retry: false});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {CommonAppModule} from '../../../app/common-app.module';
|
||||
import {NbButtonModule, NbCardModule, NbLayoutModule, NbSelectModule} from '@nebular/theme';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {RetryDialogComponent} from '@shared/modules/retry-dialog/retry-dialog.component';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
RetryDialogComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonAppModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
FlexLayoutModule,
|
||||
TranslateModule,
|
||||
NbLayoutModule,
|
||||
NbSelectModule,
|
||||
FontAwesomeModule
|
||||
],
|
||||
exports: [
|
||||
RetryDialogComponent
|
||||
]
|
||||
})
|
||||
export class RetryDialogModule { }
|
|
@ -0,0 +1,20 @@
|
|||
import {untilDestroyed} from '@ngneat/until-destroy';
|
||||
|
||||
// ToDo: PoC for handling failed requests
|
||||
function onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
console.warn(ref);
|
||||
if (ref.retry) {
|
||||
// ToDo: Send same request again
|
||||
console.warn('Retry');
|
||||
this.METHODTHATNEEDSTOBEEXECUTED(retryParameter);
|
||||
} else {
|
||||
// ToDo: Cancel action
|
||||
console.warn('Cancel');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -20,6 +20,10 @@ export class DialogServiceMock implements Required<DialogService> {
|
|||
return null;
|
||||
}
|
||||
|
||||
openRetryDialog(message: DialogMessage): NbDialogRef<any> {
|
||||
return null;
|
||||
}
|
||||
|
||||
openSecurityConfirmDialog(message: SecurityDialogMessage): NbDialogRef<SecurityConfirmDialogComponent> {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {ComponentType} from '@angular/cdk/overlay';
|
|||
import {DialogMessage, SecurityDialogMessage} from '@shared/services/dialog-service/dialog-message';
|
||||
import {ConfirmDialogComponent} from '@shared/modules/confirm-dialog/confirm-dialog.component';
|
||||
import {SecurityConfirmDialogComponent} from '@shared/modules/security-confirm-dialog/security-confirm-dialog.component';
|
||||
import {RetryDialogComponent} from '@shared/modules/retry-dialog/retry-dialog.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -44,6 +45,21 @@ export class DialogService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message.key The translation key for the shown message
|
||||
* @param message.data The data that may be used in the message translation key (Set it null if it's not required in the key)
|
||||
* @param message.title The translation key for the dialog title
|
||||
*/
|
||||
openRetryDialog(message: DialogMessage): NbDialogRef<RetryDialogComponent> {
|
||||
return this.dialog.open(RetryDialogComponent, {
|
||||
closeOnEsc: true,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false,
|
||||
context: {data: message}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message.key The translation key for the shown message
|
||||
* @param message.data The data that may be used in the message translation key (Set it null if it's not required in the key)
|
||||
|
|
|
@ -71,7 +71,7 @@ class ProjectController(private val projectService: ProjectService, private val
|
|||
@DeleteMapping("/{id}")
|
||||
fun deleteProject(@PathVariable(value = "id") id: String): Mono<ResponseEntity<ResponseBody>> {
|
||||
return this.projectService.deleteProject(id).flatMap { project: Project ->
|
||||
// If the project has pentest the will be deleted as well as all associated findings & comments
|
||||
// If the project has pentest they will be deleted as well as all associated findings & comments
|
||||
if (project.projectPentests.isNotEmpty()) {
|
||||
this.pentestDeletionService.deletePentestsAndAllAssociatedFindingsAndComments(project).collectList()
|
||||
.flatMap { prunedProject: Any ->
|
||||
|
|
Loading…
Reference in New Issue