feat: As a user I want to add a summary to the project when editing on the main page & when inside a project
This commit is contained in:
parent
3c3f005537
commit
39a1eeb8c0
|
@ -9,18 +9,28 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<h4>{{selectedProjectTitle$.getValue()}}</h4>
|
||||
<h4>{{selectedProject$.getValue().title}}</h4>
|
||||
|
||||
<div class="export-button-container">
|
||||
<div class="button-container">
|
||||
<nb-actions size="medium">
|
||||
<nb-action>
|
||||
<button nbButton
|
||||
status="button-outline-basic-text-color"
|
||||
shape="round"
|
||||
(click)="onClickEditPentestProject()">
|
||||
<fa-icon [icon]="fa.faEdit"
|
||||
class="element-icon fa-lg"></fa-icon>
|
||||
<span class="element-text">{{ 'global.action.edit' | translate }}</span>
|
||||
</button>
|
||||
</nb-action>
|
||||
<nb-action>
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
shape="round"
|
||||
(click)="onClickExportPentest()">
|
||||
<fa-icon [icon]="fa.faFileExport"
|
||||
class="export-element-icon fa-lg"></fa-icon>
|
||||
<span class="export-element-text">{{ 'global.action.export' | translate }}</span>
|
||||
class="element-icon fa-lg"></fa-icon>
|
||||
<span class="element-text">{{ 'global.action.export' | translate }}</span>
|
||||
</button>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
.export-button-container {
|
||||
.button-container {
|
||||
display: flex;
|
||||
align-content: flex-end;
|
||||
// ToDo: Fix so that longer / shorter name won't change needed margin
|
||||
margin-right: 2.25rem;
|
||||
// margin-right: 2.25rem;
|
||||
|
||||
.export-element-icon {
|
||||
.element-icon {
|
||||
}
|
||||
|
||||
.export-element-text {
|
||||
.element-text {
|
||||
padding-left: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
|
|
@ -8,14 +8,52 @@ import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
|||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
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 {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {NbActionsModule, NbIconModule} from '@nebular/theme';
|
||||
import {ProjectService} from '@shared/services/project.service';
|
||||
import {ProjectServiceMock} from '@shared/services/project.service.mock';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {NotificationService} from '@shared/services/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/notification.service.mock';
|
||||
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',
|
||||
summary: '',
|
||||
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: [],
|
||||
commentIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('ObjectiveHeaderComponent', () => {
|
||||
let component: ObjectiveHeaderComponent;
|
||||
let fixture: ComponentFixture<ObjectiveHeaderComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
|
@ -36,6 +74,12 @@ describe('ObjectiveHeaderComponent', () => {
|
|||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -43,6 +87,11 @@ describe('ObjectiveHeaderComponent', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ObjectiveHeaderComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
|
|
@ -6,7 +6,14 @@ import {Router} from '@angular/router';
|
|||
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
import {Project, ProjectDialogBody} from '@shared/models/project.model';
|
||||
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
||||
import {filter, mergeMap} from 'rxjs/operators';
|
||||
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||
import {ProjectService} from '@shared/services/project.service';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {InitProjectState} from '@shared/stores/project-state/project-state.actions';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -17,9 +24,13 @@ import {Project} from '@shared/models/project.model';
|
|||
export class ObjectiveHeaderComponent implements OnInit {
|
||||
|
||||
readonly fa = FA;
|
||||
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
selectedProject$: BehaviorSubject<Project> = new BehaviorSubject<Project>(null);
|
||||
|
||||
constructor(private store: Store,
|
||||
private readonly notificationService: NotificationService,
|
||||
private projectService: ProjectService,
|
||||
private dialogService: DialogService,
|
||||
private projectDialogService: ProjectDialogService,
|
||||
private readonly router: Router) {
|
||||
}
|
||||
|
||||
|
@ -28,7 +39,7 @@ export class ObjectiveHeaderComponent implements OnInit {
|
|||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
this.selectedProjectTitle$.next(selectedProject?.title);
|
||||
this.selectedProject$.next(selectedProject);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
|
@ -46,6 +57,36 @@ export class ObjectiveHeaderComponent implements OnInit {
|
|||
).finally();
|
||||
}
|
||||
|
||||
onClickEditPentestProject(): void {
|
||||
this.projectDialogService.openProjectDialog(
|
||||
ProjectDialogComponent,
|
||||
this.selectedProject$.getValue(),
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: ProjectDialogBody) => this.projectService.updateProject(this.selectedProject$.getValue().id, value)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (project: Project) => {
|
||||
this.store.dispatch(new InitProjectState(
|
||||
project,
|
||||
[],
|
||||
[]
|
||||
)).pipe(untilDestroyed(this)).subscribe();
|
||||
this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickExportPentest(): void {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.info('To be implemented..');
|
||||
|
|
|
@ -30,6 +30,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -21,6 +21,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -30,6 +30,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -21,6 +21,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -21,6 +21,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -67,7 +67,7 @@ describe('ProjectOverviewComponent', () => {
|
|||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
{provide: NotificationService, useClass: NotificationServiceMock}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
|
|
@ -7,16 +7,55 @@ import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
|||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {SessionState} from '@shared/stores/session-state/session-state';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {NbCardModule, NbLayoutModule} from '@nebular/theme';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
import {ObjectiveOverviewModule} from '../../objective-overview';
|
||||
import {NotificationService} from '@shared/services/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/notification.service.mock';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {ProjectService} from '@shared/services/project.service';
|
||||
import {ProjectServiceMock} from '@shared/services/project.service.mock';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||
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',
|
||||
summary: '',
|
||||
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: [],
|
||||
commentIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('ProjectComponent', () => {
|
||||
let component: ProjectComponent;
|
||||
let fixture: ComponentFixture<ProjectComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
|
@ -37,12 +76,16 @@ describe('ProjectComponent', () => {
|
|||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([SessionState]),
|
||||
NgxsModule.forRoot([ProjectState]),
|
||||
HttpClientModule,
|
||||
HttpClientTestingModule
|
||||
],
|
||||
providers: [
|
||||
KeycloakService
|
||||
KeycloakService,
|
||||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useClass: NotificationServiceMock}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -50,6 +93,11 @@ describe('ProjectComponent', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"action.return": "Zurück",
|
||||
"action.exit": "Beenden",
|
||||
"action.update": "Speichern",
|
||||
"action.edit": "Editieren",
|
||||
"action.export": "Exportieren",
|
||||
"action.reset": "Zurücksetzen",
|
||||
"action.yes": "Ja",
|
||||
|
@ -46,9 +47,12 @@
|
|||
"title.label": "Projekt Titel",
|
||||
"client.label": "Name des Auftraggebers",
|
||||
"tester.label": "Name des Pentester",
|
||||
"summary.label": "Zusammenfassung",
|
||||
"summary.placeholder": "Sollte eine Zusammenfassung, einen Ansatz, einen Umfang und eine Bewertungsübersicht sowie allgemeine Empfehlungen enthalten",
|
||||
"title": "Titel",
|
||||
"client": "Klient",
|
||||
"tester": "Tester",
|
||||
"summary": "Zusammenfassung",
|
||||
"createdAt": "Erstellt am",
|
||||
"overview": {
|
||||
"add.project": "Projekt hinzufügen",
|
||||
|
@ -69,7 +73,8 @@
|
|||
"validationMessage": {
|
||||
"titleRequired": "Titel ist erforderlich.",
|
||||
"clientRequired": "Klient ist erforderlich.",
|
||||
"testerRequired": "Tester ist erforderlich."
|
||||
"testerRequired": "Tester ist erforderlich.",
|
||||
"summaryRequired": "Zusammenfassung ist erforderlich."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "Keine Projekte gefunden",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"action.return": "Return",
|
||||
"action.exit": "Exit",
|
||||
"action.update": "Update",
|
||||
"action.edit": "Edit",
|
||||
"action.export": "Export",
|
||||
"action.reset": "Reset",
|
||||
"action.yes": "Yes",
|
||||
|
@ -46,9 +47,12 @@
|
|||
"title.label": "Project Title",
|
||||
"client.label": "Name of Client",
|
||||
"tester.label": "Name of Pentester",
|
||||
"summary.label": "Summary",
|
||||
"summary.placeholder": "Should include Executive Summary, Approach, Scope and Assessment Overview as well as General Recommendations",
|
||||
"title": "Title",
|
||||
"client": "Client",
|
||||
"tester": "Tester",
|
||||
"summary": "Summary",
|
||||
"createdAt": "Created at",
|
||||
"overview": {
|
||||
"add.project": "Add Project",
|
||||
|
@ -69,7 +73,8 @@
|
|||
"validationMessage": {
|
||||
"titleRequired": "Title is required.",
|
||||
"clientRequired": "Client is required.",
|
||||
"testerRequired": "Tester is required."
|
||||
"testerRequired": "Tester is required.",
|
||||
"summaryRequired": "Summary is required."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "No projects found",
|
||||
|
|
|
@ -40,6 +40,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -38,6 +38,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
|
|
|
@ -28,6 +28,27 @@
|
|||
</span>
|
||||
</ng-template>
|
||||
</nb-form-field>
|
||||
<!-- Textarea styles -->
|
||||
<nb-form-field *ngSwitchCase="'formText'" class="project-form-field">
|
||||
<label for="{{fieldConfig.fieldName}}" class="label">
|
||||
{{fieldConfig.labelKey | translate}}
|
||||
</label>
|
||||
<textarea formControlName="{{fieldConfig.fieldName}}"
|
||||
type="formText" required fullWidth
|
||||
id="{{fieldConfig.fieldName}}" nbInput
|
||||
class="form-field form-textarea"
|
||||
[status]="projectFormGroup.get(fieldConfig.fieldName).dirty ? (projectFormGroup.get(fieldConfig.fieldName).invalid ? 'danger' : 'basic') : 'basic'"
|
||||
placeholder="{{fieldConfig.placeholder | translate}}">
|
||||
</textarea>
|
||||
<!-- FIXME: when the bug (https://github.com/angular/components/issues/7739) is fixed -->
|
||||
<ng-template ngFor let-error [ngForOf]="fieldConfig.errors"
|
||||
*ngIf="projectFormGroup.get(fieldConfig.fieldName).dirty">
|
||||
<span class="error-text"
|
||||
*ngIf="projectFormGroup.get(fieldConfig.fieldName)?.hasError(error.errorCode) && error.errorCode === 'required'">
|
||||
{{error.translationKey | translate}}
|
||||
</span>
|
||||
</ng-template>
|
||||
</nb-form-field>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</form>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
@import '../../../assets/@theme/styles/themes';
|
||||
|
||||
.project-dialog {
|
||||
width: 25.25rem;
|
||||
height: 35rem;
|
||||
width: 40rem !important;
|
||||
height: 42.25rem;
|
||||
|
||||
.project-dialog-header {
|
||||
height: 8vh;
|
||||
|
@ -21,10 +21,17 @@
|
|||
}
|
||||
|
||||
.form-field {
|
||||
width: 18rem;
|
||||
width: 26.75rem;
|
||||
// width: 30rem !important;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
width: 26.75rem !important;
|
||||
// width: 30rem !important;
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
float: left;
|
||||
color: nb-theme(color-danger-default);
|
||||
|
|
|
@ -91,6 +91,7 @@ export const mockProject: Project = {
|
|||
title: 'Test Project',
|
||||
client: 'Testclient',
|
||||
tester: 'Testpentester',
|
||||
summary: '',
|
||||
createdAt: new Date(),
|
||||
testingProgress: 0,
|
||||
createdBy: 'UID-11-12-13'
|
||||
|
|
|
@ -43,7 +43,8 @@ export class ProjectDialogComponent implements OnInit {
|
|||
this.dialogRef.close({
|
||||
title: value.projectTitle,
|
||||
client: value.projectClient,
|
||||
tester: value.projectTester
|
||||
tester: value.projectTester,
|
||||
summary: value.projectSummary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,19 @@ export class ProjectDialogService {
|
|||
errors: [
|
||||
{errorCode: 'required', translationKey: 'project.validationMessage.testerRequired'}
|
||||
]
|
||||
},
|
||||
projectSummary: {
|
||||
fieldName: 'projectSummary',
|
||||
type: 'formText',
|
||||
labelKey: 'project.summary.label',
|
||||
placeholder: 'project.summary.placeholder',
|
||||
controlsConfig: [
|
||||
{value: project ? project.summary : '', disabled: !project},
|
||||
[project ? Validators.required : []]
|
||||
],
|
||||
errors: [
|
||||
{errorCode: 'required', translationKey: 'project.validationMessage.summaryRequired'}
|
||||
]
|
||||
}
|
||||
},
|
||||
options: []
|
||||
|
|
|
@ -41,6 +41,7 @@ describe('ProjectService', () => {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: dummyDate,
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
};
|
||||
|
@ -90,6 +91,7 @@ describe('ProjectService', () => {
|
|||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: dummyDate,
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
};
|
||||
|
|
|
@ -41,11 +41,13 @@ class ReportController(private val apiService: APIService, private val reportSer
|
|||
jacksonObjectMapper().readValue<ProjectReport>(jsonProjectReportString)
|
||||
return this.reportService.createReport(jsonProjectReportCollection, "pdf").map { reportClassLoaderFilePatch ->
|
||||
val reportRessourceStream = ReportController::class.java.getResourceAsStream(reportClassLoaderFilePatch)
|
||||
// Todo: Fix Error with IOUtils.toByteArray(reportRessourceStream) on first start of application
|
||||
val response = IOUtils.toByteArray(reportRessourceStream)
|
||||
this.reportService.cleanUpFiles()
|
||||
ResponseEntity.ok().body(response)
|
||||
}.switchIfEmpty {
|
||||
Mono.just(notFound().build<ByteArray>())
|
||||
}.doOnSuccess {
|
||||
this.reportService.cleanUpFiles()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
<textElement>
|
||||
<font size="12"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{summary}]]></textFieldExpression>
|
||||
<textFieldExpression><![CDATA[(($F{summary}.length() == 0) ? "" + $F{client} +" contracted " + $F{tester} + " to perform a Penetration Test to identify security weaknesses, determine the impact to " + $F{client} +", document all findings in a clear and repeatable manner, and provide remediation recommendations." : $F{summary})]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="10" width="380" height="20" forecolor="#232B44" uuid="b508eb27-8cf7-40f3-86e8-6b7c9328d919"/>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 220 KiB |
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue