From 3bbfc9c4d3d3a8f801ef3691298de223cea10dcc Mon Sep 17 00:00:00 2001 From: Alejandro Saenz Date: Thu, 21 May 2020 17:14:41 -0400 Subject: [PATCH] feat(assessment form and report): dynamic tester association to asssment Added a ManyToMany relation between the User and Assessment models. Added a muliple select option to the assessment.component. Added APIs to get users. Patched the create and update assessment APIs. Updated the report to retrieve testers. BREAKING CHANGE: ManyToMany relationship has been created between the User and Assessment models. API's have been updated for this change. New API's created to retrieve users. feat #52 --- frontend/package-lock.json | 5 + frontend/package.json | 1 + frontend/src/app/app-routing.module.ts | 32 +- frontend/src/app/app.module.ts | 11 +- .../src/app/assessment-form/Assessment.ts | 4 +- .../assessment-form.component.html | 91 ++---- .../assessment-form.component.ts | 47 ++- frontend/src/app/classes/User.ts | 13 + frontend/src/app/report/report.component.html | 28 +- .../user-profile/user-profile.component.ts | 3 +- frontend/src/app/user.service.ts | 5 +- frontend/src/styles.scss | 2 + src/app.ts | 1 + src/entity/Assessment.ts | 6 +- src/routes/assessment.controller.ts | 294 ++++++++++-------- src/routes/user.controller.ts | 35 ++- 16 files changed, 334 insertions(+), 244 deletions(-) create mode 100644 frontend/src/app/classes/User.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 206e069b..d1d1048d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2948,6 +2948,11 @@ } } }, + "@ng-select/ng-select": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-4.0.0.tgz", + "integrity": "sha512-B6OevKG9/LlbZ9aPHcmiRRQBIIdk41cJ1wn4UHOlm/0225+jtW7IWA/7Q0iv5S6gys1ieyY9+BAqfTz1elBTUw==" + }, "@ngtools/webpack": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 12c043fc..05a96666 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.25", "@fortawesome/free-brands-svg-icons": "^5.11.2", "@fortawesome/free-solid-svg-icons": "^5.11.2", + "@ng-select/ng-select": "^4.0.0", "core-js": "^2.5.4", "ngx-markdown": "^8.2.1", "rxjs": "~6.5.4", diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 270bfd2e..46ae4015 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -26,6 +26,8 @@ import { InviteUserComponent } from './invite-user/invite-user.component'; import { RegisterComponent } from './register/register.component'; import { UserProfileComponent } from './user-profile/user-profile.component'; import { UserService } from './user.service'; +import { forkJoin } from 'rxjs'; +import { map } from 'rxjs/internal/operators/map'; @Injectable() export class AssetsResolver implements Resolve { constructor(private apiService: AppService) {} @@ -43,12 +45,29 @@ export class AssetResolver implements Resolve { } @Injectable() export class AssessmentResolver implements Resolve { - constructor(private apiService: AppService) {} + constructor( + private apiService: AppService, + private userService: UserService + ) {} resolve(route: ActivatedRouteSnapshot) { - return this.apiService.getAssessment( - route.params.assetId, - route.params.assessmentId - ); + if (route.params.assetId && route.params.assessmentId) { + return forkJoin([ + this.apiService.getAssessment( + route.params.assetId, + route.params.assessmentId + ), + this.userService.getUsers(), + ]).pipe( + map((result) => { + return { + assessment: result[0], + testers: result[1], + }; + }) + ); + } else { + return this.userService.getUsers(); + } } } @Injectable() @@ -194,12 +213,13 @@ const routes: Routes = [ { path: 'organization/:orgId/asset/:assetId/assessment', component: AssessmentFormComponent, + resolve: { result: AssessmentResolver }, canActivate: [AuthGuard], }, { path: 'organization/:orgId/asset/:assetId/assessment/:assessmentId', component: AssessmentFormComponent, - resolve: { assessment: AssessmentResolver }, + resolve: { result: AssessmentResolver }, canActivate: [AuthGuard], }, { diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 8c78d70c..ebe2e622 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -8,7 +8,7 @@ import { AppComponent } from './app.component'; import { NavbarComponent } from './navbar/navbar.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { AlertModule } from './alert/alert.module'; - +import { NgSelectModule } from '@ng-select/ng-select'; import { AppService } from './app.service'; import { LoaderService } from './loader.service'; import { AuthGuard } from './auth.guard'; @@ -53,7 +53,7 @@ import { UserProfileComponent } from './user-profile/user-profile.component'; PasswordResetComponent, InviteUserComponent, RegisterComponent, - UserProfileComponent + UserProfileComponent, ], imports: [ BrowserModule, @@ -62,15 +62,16 @@ import { UserProfileComponent } from './user-profile/user-profile.component'; ReactiveFormsModule, FontAwesomeModule, MarkdownModule.forRoot(), - AlertModule + AlertModule, + NgSelectModule, ], providers: [ AppService, DatePipe, LoaderService, { provide: HTTP_INTERCEPTORS, useClass: AppInterceptor, multi: true }, - AuthGuard + AuthGuard, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) export class AppModule {} diff --git a/frontend/src/app/assessment-form/Assessment.ts b/frontend/src/app/assessment-form/Assessment.ts index b725736f..be02edac 100644 --- a/frontend/src/app/assessment-form/Assessment.ts +++ b/frontend/src/app/assessment-form/Assessment.ts @@ -1,4 +1,5 @@ import { Url } from 'url'; +import { User } from '../classes/User'; export class Assessment { constructor( @@ -12,6 +13,7 @@ export class Assessment { public scope: string, public tag: number, public startDate: Date, - public endDate: Date + public endDate: Date, + public testers: User[] ) {} } diff --git a/frontend/src/app/assessment-form/assessment-form.component.html b/frontend/src/app/assessment-form/assessment-form.component.html index 7febbe59..4eda9db6 100644 --- a/frontend/src/app/assessment-form/assessment-form.component.html +++ b/frontend/src/app/assessment-form/assessment-form.component.html @@ -2,85 +2,42 @@
- + - + - + - + - + - + + + + + × + {{item.firstName}} {{item.lastName}} + + + {{item.firstName}} {{item.lastName}} + + - + - +
- -
diff --git a/frontend/src/app/assessment-form/assessment-form.component.ts b/frontend/src/app/assessment-form/assessment-form.component.ts index f1591ba5..5e970516 100644 --- a/frontend/src/app/assessment-form/assessment-form.component.ts +++ b/frontend/src/app/assessment-form/assessment-form.component.ts @@ -4,11 +4,12 @@ import { AppService } from '../app.service'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Assessment } from './Assessment'; import { AlertService } from '../alert/alert.service'; +import { User } from '../classes/User'; @Component({ selector: 'app-assessment-form', templateUrl: './assessment-form.component.html', - styleUrls: ['./assessment-form.component.sass'] + styleUrls: ['./assessment-form.component.sass'], }) export class AssessmentFormComponent implements OnInit, OnChanges { public assessmentModel: Assessment; @@ -16,6 +17,7 @@ export class AssessmentFormComponent implements OnInit, OnChanges { public assetId: number; public assessmentId: number; public orgId: number; + public testers: User[] = []; constructor( public appService: AppService, private fb: FormBuilder, @@ -27,11 +29,18 @@ export class AssessmentFormComponent implements OnInit, OnChanges { } ngOnInit() { - this.activatedRoute.data.subscribe(({ assessment }) => { - if (assessment) { - assessment.startDate = this.transformDate(assessment.startDate); - assessment.endDate = this.transformDate(assessment.endDate); - this.assessmentForm.patchValue(assessment); + this.activatedRoute.data.subscribe(({ result }) => { + if (result.assessment) { + result.assessment.startDate = this.transformDate( + result.assessment.startDate + ); + result.assessment.endDate = this.transformDate( + result.assessment.endDate + ); + this.testers = result.testers; + this.assessmentForm.patchValue(result.assessment); + } else { + this.testers = result; } }); this.activatedRoute.params.subscribe((params) => { @@ -71,7 +80,8 @@ export class AssessmentFormComponent implements OnInit, OnChanges { scope: this.assessmentModel.scope, tag: this.assessmentModel.tag, startDate: this.assessmentModel.startDate, - endDate: this.assessmentModel.endDate + endDate: this.assessmentModel.endDate, + testers: this.assessmentModel.testers, }); } @@ -88,7 +98,8 @@ export class AssessmentFormComponent implements OnInit, OnChanges { scope: ['', [Validators.required]], tag: ['', []], startDate: ['', [Validators.required]], - endDate: ['', [Validators.required]] + endDate: ['', [Validators.required]], + testers: ['', [Validators.required]], }); } @@ -108,16 +119,20 @@ export class AssessmentFormComponent implements OnInit, OnChanges { */ createOrUpdateAssessment(assessment: Assessment) { if (this.assessmentId) { - this.appService.updateAssessment(assessment, this.assessmentId, this.assetId).subscribe((res: string) => { - this.navigateToAssessments(); - this.alertService.success(res); - }); + this.appService + .updateAssessment(assessment, this.assessmentId, this.assetId) + .subscribe((res: string) => { + this.navigateToAssessments(); + this.alertService.success(res); + }); } else { this.assessmentModel.asset = this.assetId; - this.appService.createAssessment(this.assessmentModel).subscribe((res: string) => { - this.navigateToAssessments(); - this.alertService.success(res); - }); + this.appService + .createAssessment(this.assessmentModel) + .subscribe((res: string) => { + this.navigateToAssessments(); + this.alertService.success(res); + }); } } diff --git a/frontend/src/app/classes/User.ts b/frontend/src/app/classes/User.ts new file mode 100644 index 00000000..f0ad18a9 --- /dev/null +++ b/frontend/src/app/classes/User.ts @@ -0,0 +1,13 @@ +export class User { + id: number; + firstName: string; + lastName: string; + title: string; + + constructor(id: number, firstName: string, lastName: string, title: string) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.title = title; + } +} diff --git a/frontend/src/app/report/report.component.html b/frontend/src/app/report/report.component.html index 8733f430..8476416f 100644 --- a/frontend/src/app/report/report.component.html +++ b/frontend/src/app/report/report.component.html @@ -42,25 +42,25 @@

Executive Summary


-
+

Application Security Team

- - - - - - - - - - - - + + + + + + + + + + + +
NamePosition
John 117Master Chief
CortanaPr. Artificial Intelligence
NamePosition
{{ tester?.firstName }} {{tester?.lastName}}{{ tester?.title }}
-
+

Tools and Methodology

  • diff --git a/frontend/src/app/user-profile/user-profile.component.ts b/frontend/src/app/user-profile/user-profile.component.ts index 7ac7217c..2bb89738 100644 --- a/frontend/src/app/user-profile/user-profile.component.ts +++ b/frontend/src/app/user-profile/user-profile.component.ts @@ -3,7 +3,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { AuthService } from '../auth.service'; import { Router, ActivatedRoute } from '@angular/router'; import { AlertService } from '../alert/alert.service'; -import { User } from '../interfaces/User'; +import { User } from '../classes/User'; import { UserService } from '../user.service'; @Component({ @@ -57,6 +57,7 @@ export class UserProfileComponent implements OnInit { this.userForm.enable(); } else { const userInfo: User = { + id: null, firstName: form.value.firstName, lastName: form.value.lastName, title: form.value.title, diff --git a/frontend/src/app/user.service.ts b/frontend/src/app/user.service.ts index 1b0bdceb..6ce450d9 100644 --- a/frontend/src/app/user.service.ts +++ b/frontend/src/app/user.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment } from '../environments/environment'; -import { User } from './interfaces/User'; +import { User } from './classes/User'; @Injectable({ providedIn: 'root', }) @@ -21,6 +21,9 @@ export class UserService { return this.http.get(`${this.api}/user`); } + getUsers() { + return this.http.get(`${this.api}/users`); + } patchUser(user: User) { return this.http.patch(`${this.api}/user`, user); } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index bc0b286a..0ae5bd88 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1,3 +1,5 @@ +@import '~@ng-select/ng-select/themes/default.theme.css'; + .btn-primary { background-color: #ae0a0a; border-color: #ae0a0a; diff --git a/src/app.ts b/src/app.ts index 9cc524d9..8a6c93f1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -48,6 +48,7 @@ createConnection().then((_) => { app.post('/api/user/invite', jwtMiddleware.checkToken, userController.invite); app.patch('/api/user', jwtMiddleware.checkToken, userController.patch); app.get('/api/user', jwtMiddleware.checkToken, userController.getUser); + app.get('/api/users', jwtMiddleware.checkToken, userController.getUsers); app.get('/api/user/verify/:uuid', userController.verify); app.patch('/api/forgot-password', authController.forgotPassword); app.patch('/api/password-reset', authController.resetPassword); diff --git a/src/entity/Assessment.ts b/src/entity/Assessment.ts index 3836b1ee..1d68d701 100644 --- a/src/entity/Assessment.ts +++ b/src/entity/Assessment.ts @@ -1,7 +1,8 @@ -import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany } from 'typeorm'; +import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany, ManyToMany, JoinTable } from 'typeorm'; import { Asset } from './Asset'; import { Vulnerability } from './Vulnerability'; import { IsUrl, IsDate, MaxLength, IsString } from 'class-validator'; +import { User } from './User'; @Entity() export class Assessment { @@ -34,4 +35,7 @@ export class Assessment { asset: Asset; @OneToMany((type) => Vulnerability, (vuln) => vuln.assessment) vulnerabilities: Vulnerability[]; + @ManyToMany((type) => User) + @JoinTable() + testers: User[]; } diff --git a/src/routes/assessment.controller.ts b/src/routes/assessment.controller.ts index 3c3586da..123f6968 100644 --- a/src/routes/assessment.controller.ts +++ b/src/routes/assessment.controller.ts @@ -1,12 +1,13 @@ import { UserRequest } from '../interfaces/user-request.interface'; import { Response } from 'express'; -import { getConnection } from 'typeorm' +import { getConnection } from 'typeorm'; import { Assessment } from '../entity/Assessment'; import { Asset } from '../entity/Asset'; import { validate } from 'class-validator'; import { Vulnerability } from '../entity/Vulnerability'; import { Organization } from '../entity/Organization'; import { Report } from '../classes/Report'; +const userController = require('../routes/user.controller'); /** * @description Get assessments by asset ID @@ -15,20 +16,22 @@ import { Report } from '../classes/Report'; * @returns Asset assessments */ const getAssessmentsByAssetId = async (req: UserRequest, res: Response) => { - if (!req.params.id) { - return res.status(400).json('Invalid Assessment UserRequest'); - } - if (isNaN(+req.params.id)) { - return res.status(400).json('Invalid Asset ID'); - } - const assessment = await getConnection().getRepository(Assessment).find({ - where: { asset: req.params.id } + if (!req.params.id) { + return res.status(400).json('Invalid Assessment UserRequest'); + } + if (isNaN(+req.params.id)) { + return res.status(400).json('Invalid Asset ID'); + } + const assessment = await getConnection() + .getRepository(Assessment) + .find({ + where: { asset: req.params.id } }); - if (!assessment) { - return res.status(404).json('Assessments do not exist'); - } - res.status(200).json(assessment); -} + if (!assessment) { + return res.status(404).json('Assessments do not exist'); + } + res.status(200).json(assessment); +}; /** * @description Get all vulnerabilities by assessment * @param {UserRequest} req @@ -36,20 +39,22 @@ const getAssessmentsByAssetId = async (req: UserRequest, res: Response) => { * @returns assessment vulnerabilities */ const getAssessmentVulns = async (req: UserRequest, res: Response) => { - if (!req.params.id) { - return res.status(400).json('Invalid Vulnerability UserRequest'); - } - if (isNaN(+req.params.id)) { - return res.status(400).json('Invalid Assessment ID'); - } - const vulnerabilities = await getConnection().getRepository(Vulnerability).find({ - where: { assessment: req.params.id } + if (!req.params.id) { + return res.status(400).json('Invalid Vulnerability UserRequest'); + } + if (isNaN(+req.params.id)) { + return res.status(400).json('Invalid Assessment ID'); + } + const vulnerabilities = await getConnection() + .getRepository(Vulnerability) + .find({ + where: { assessment: req.params.id } }); - if (!vulnerabilities) { - return res.status(404).json('Vulnerabilities do not exist'); - } - res.status(200).json(vulnerabilities); -} + if (!vulnerabilities) { + return res.status(404).json('Vulnerabilities do not exist'); + } + res.status(200).json(vulnerabilities); +}; /** * @description Create assessment * @param {UserRequest} req @@ -57,32 +62,37 @@ const getAssessmentVulns = async (req: UserRequest, res: Response) => { * @returns success message */ const createAssessment = async (req: UserRequest, res: Response) => { - if (isNaN(req.body.asset)) { - return res.status(400).json('Asset ID is invalid'); - } - const asset = await getConnection().getRepository(Asset).findOne(req.body.asset); - if (!asset) { - return res.status(404).json('Asset does not exist'); - } - const assessment = new Assessment(); - assessment.asset = asset; - assessment.name = req.body.name; - assessment.executiveSummary = req.body.executiveSummary; - assessment.jiraId = req.body.jiraId; - assessment.testUrl = req.body.testUrl; - assessment.prodUrl = req.body.prodUrl; - assessment.scope = req.body.scope; - assessment.tag = req.body.tag; - assessment.startDate = new Date(req.body.startDate); - assessment.endDate = new Date(req.body.endDate); - const errors = await validate(assessment); - if (errors.length > 0) { - return res.status(400).send('Assessment form validation failed'); - } else { - await getConnection().getRepository(Assessment).save(assessment); - res.status(200).json('Assessment created succesfully'); - } -} + if (isNaN(req.body.asset)) { + return res.status(400).json('Asset ID is invalid'); + } + const asset = await getConnection().getRepository(Asset).findOne(req.body.asset); + if (!asset) { + return res.status(404).json('Asset does not exist'); + } + if (!req.body.testers) { + return res.status(400).json('No testers have been selected'); + } + const testers = await userController.getUsersById(req.body.testers); + const assessment = new Assessment(); + assessment.asset = asset; + assessment.name = req.body.name; + assessment.executiveSummary = req.body.executiveSummary; + assessment.jiraId = req.body.jiraId; + assessment.testUrl = req.body.testUrl; + assessment.prodUrl = req.body.prodUrl; + assessment.scope = req.body.scope; + assessment.tag = req.body.tag; + assessment.startDate = new Date(req.body.startDate); + assessment.endDate = new Date(req.body.endDate); + assessment.testers = testers; + const errors = await validate(assessment); + if (errors.length > 0) { + return res.status(400).send('Assessment form validation failed'); + } else { + await getConnection().getRepository(Assessment).save(assessment); + res.status(200).json('Assessment created succesfully'); + } +}; /** * @description Get asset assessment by ID * @param {UserRequest} req @@ -90,17 +100,25 @@ const createAssessment = async (req: UserRequest, res: Response) => { * @returns assessment */ const getAssessmentById = async (req: UserRequest, res: Response) => { - if (!req.params.assessmentId) { - return res.status(400).send('Invalid assessment request'); - } - if (isNaN(+req.params.assessmentId)) { - return res.status(400).json('Invalid Assessment ID'); - } - const assessment = await getConnection().getRepository(Assessment).findOne(req.params.assessmentId); - if (!assessment) { - return res.status(404).json('Assessment does not exist'); - } - res.status(200).json(assessment); + if (!req.params.assessmentId) { + return res.status(400).send('Invalid assessment request'); + } + if (isNaN(+req.params.assessmentId)) { + return res.status(400).json('Invalid Assessment ID'); + } + const assessment = await getConnection() + .getRepository(Assessment) + .createQueryBuilder('assessment') + .leftJoinAndSelect('assessment.testers', 'tester') + .where('assessment.id = :assessmentId', { + assessmentId: req.params.assessmentId + }) + .select(['assessment', 'tester.firstName', 'tester.lastName', 'tester.title', 'tester.id']) + .getOne(); + if (!assessment) { + return res.status(404).json('Assessment does not exist'); + } + res.status(200).json(assessment); }; /** * @description Update assessment @@ -109,31 +127,37 @@ const getAssessmentById = async (req: UserRequest, res: Response) => { * @returns success message */ const updateAssessmentById = async (req: UserRequest, res: Response) => { - if (!req.params.assessmentId) { - return res.status(400).send('Invalid assessment UserRequest'); - } - if (isNaN(+req.params.assessmentId)) { - return res.status(400).json('Invalid Assessment ID'); - } - let assessment = await getConnection().getRepository(Assessment).findOne(req.params.assessmentId); - if (!assessment) { - return res.status(404).json('Assessment does not exist'); - } - const assessmentId = assessment.id; - delete req.body.asset; - assessment = req.body; - assessment.id = assessmentId; - if (assessment.startDate > assessment.endDate) { - return res.status(400).send('The assessment start date can not be later than the end date'); - } - const errors = await validate(assessment); - if (errors.length > 0) { - return res.status(400).send('Assessment form validation failed'); - } else { - await getConnection().getRepository(Assessment).save(assessment); - res.status(200).json('Assessment patched successfully'); - } -} + if (!req.params.assessmentId) { + return res.status(400).send('Invalid assessment UserRequest'); + } + if (isNaN(+req.params.assessmentId)) { + return res.status(400).json('Invalid Assessment ID'); + } + let assessment = await getConnection() + .getRepository(Assessment) + .findOne(req.params.assessmentId, { relations: ['testers'] }); + if (!assessment) { + return res.status(404).json('Assessment does not exist'); + } + if (!req.body.testers) { + return res.status(400).json('No testers have been selected'); + } + const assessmentId = assessment.id; + delete req.body.asset; + assessment = req.body; + assessment.id = assessmentId; + assessment.testers = await userController.getUsersById(req.body.testers); + if (assessment.startDate > assessment.endDate) { + return res.status(400).send('The assessment start date can not be later than the end date'); + } + const errors = await validate(assessment); + if (errors.length > 0) { + return res.status(400).send('Assessment form validation failed'); + } else { + await getConnection().getRepository(Assessment).save(assessment); + res.status(200).json('Assessment patched successfully'); + } +}; /** * @description Query information for assessment report * @param {UserRequest} req @@ -141,48 +165,56 @@ const updateAssessmentById = async (req: UserRequest, res: Response) => { * @returns report information */ const queryReportDataByAssessment = async (req: UserRequest, res: Response) => { - if (!req.params.assessmentId) { - return res.status(400).send('Invalid report UserRequest'); - } - if (isNaN(+req.params.assessmentId)) { - return res.status(400).json('Invalid Assessment ID'); - } - const assessment = await getConnection().getRepository(Assessment).findOne(req.params.assessmentId, { relations: ['asset'] }); - const asset = await getConnection().getRepository(Asset).findOne(assessment.asset.id, { - relations: ['organization'] + if (!req.params.assessmentId) { + return res.status(400).send('Invalid report UserRequest'); + } + if (isNaN(+req.params.assessmentId)) { + return res.status(400).json('Invalid Assessment ID'); + } + const assessment = await getConnection() + .getRepository(Assessment) + .createQueryBuilder('assessment') + .leftJoinAndSelect('assessment.testers', 'tester') + .where('assessment.id = :assessmentId', { + assessmentId: req.params.assessmentId + }) + .leftJoinAndSelect('assessment.asset', 'asset') + .select(['assessment', 'tester.firstName', 'tester.lastName', 'tester.title', 'tester.id']) + .getOne(); + const assessmentForId = await getConnection() + .getRepository(Assessment) + .findOne(req.params.assessmentId, { relations: ['asset'] }); + const asset = await getConnection() + .getRepository(Asset) + .findOne(assessmentForId.asset.id, { + relations: ['organization'] }); - const organization = await getConnection().getRepository(Organization).findOne(asset.organization.id); - const vulnerabilities = await getConnection().getRepository(Vulnerability) - .createQueryBuilder('vuln') - .leftJoinAndSelect('vuln.screenshots', 'screenshot') - .leftJoinAndSelect('vuln.problemLocations', 'problemLocation') - .leftJoinAndSelect('vuln.resources', 'resource') - .where('vuln.assessmentId = :assessmentId', { - assessmentId: assessment.id - }) - .select([ - 'vuln', - 'screenshot.id', - 'screenshot.originalname', - 'screenshot.mimetype', - 'problemLocation', - 'resource' - ]) - .getMany(); - const report = new Report(); - report.org = organization; - report.asset = asset; - report.assessment = assessment; - report.vulns = vulnerabilities; - report.companyName = process.env.COMPANY_NAME; - res.status(200).json(report); -} + const organization = await getConnection().getRepository(Organization).findOne(asset.organization.id); + const vulnerabilities = await getConnection() + .getRepository(Vulnerability) + .createQueryBuilder('vuln') + .leftJoinAndSelect('vuln.screenshots', 'screenshot') + .leftJoinAndSelect('vuln.problemLocations', 'problemLocation') + .leftJoinAndSelect('vuln.resources', 'resource') + .where('vuln.assessmentId = :assessmentId', { + assessmentId: assessment.id + }) + .select(['vuln', 'screenshot.id', 'screenshot.originalname', 'screenshot.mimetype', 'problemLocation', 'resource']) + .getMany(); + const report = new Report(); + report.org = organization; + report.asset = asset; + report.assessment = assessment; + report.vulns = vulnerabilities; + report.companyName = process.env.COMPANY_NAME; + res.status(200).json(report); +}; module.exports = { - getAssessmentsByAssetId, - getAssessmentVulns, - createAssessment, - getAssessmentById, - updateAssessmentById, - queryReportDataByAssessment -} \ No newline at end of file + getAssessmentsByAssetId, + getAssessmentVulns, + createAssessment, + getAssessmentById, + updateAssessmentById, + queryReportDataByAssessment +}; diff --git a/src/routes/user.controller.ts b/src/routes/user.controller.ts index d2753d11..48918dd2 100644 --- a/src/routes/user.controller.ts +++ b/src/routes/user.controller.ts @@ -207,6 +207,37 @@ const getUser = async (req: UserRequest, res: Response) => { delete user.id; return res.status(200).json(user); }; +/** + * @description Get Users + * @param {UserRequest} req + * @param {Response} res + * @returns user array + */ +const getUsers = async (req: UserRequest, res: Response) => { + const users = await getConnection() + .getRepository(User) + .createQueryBuilder('user') + .where('user.active = true') + .select(['user.id', 'user.firstName', 'user.lastName', 'user.title']) + .getMany(); + return res.status(200).json(users); +}; +/** + * @description Get user IDs and validate users + * @param {UserRequest} req + * @param {Response} res + * @returns User array + */ +const getUsersById = async (userIds: number[]) => { + const userArray: User[] = []; + for (const iterator of userIds) { + const user = await getConnection().getRepository(User).findOne(iterator); + if (user) { + userArray.push(user); + } + } + return userArray; +}; module.exports = { create, verify, @@ -214,5 +245,7 @@ module.exports = { invite, register, patch, - getUser + getUser, + getUsers, + getUsersById };