Skip to content

Commit 949c39c

Browse files
author
Daniel Haselhan
committed
Add Virus Scanning to ALCS
1 parent fc660f4 commit 949c39c

File tree

33 files changed

+483
-99
lines changed

33 files changed

+483
-99
lines changed

alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ <h4>{{ title }} Document</h4>
99
</div>
1010
<input hidden type="file" #fileInput (change)="uploadFile($event)" placeholder="Upload file" />
1111
<button
12+
*ngIf="!pendingFile && !existingFile"
1213
class="full-width upload-button"
1314
mat-flat-button
1415
color="accent"
15-
*ngIf="!pendingFile && !existingFile"
16+
[ngClass]="{
17+
error: showVirusError
18+
}"
1619
(click)="fileInput.click()"
1720
>
1821
Upload
@@ -34,6 +37,9 @@ <h4>{{ title }} Document</h4>
3437
<mat-icon>close</mat-icon>Remove
3538
</button>
3639
</div>
40+
<mat-error class="left" style="display: flex" *ngIf="showVirusError">
41+
<mat-icon>warning</mat-icon>&nbsp;A virus was detected in the file. Choose another file and try again.
42+
</mat-error>
3743
</div>
3844

3945
<div class="double">

alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use '../../../../../../../styles/colors';
2+
13
.form {
24
display: grid;
35
grid-template-columns: 1fr 1fr;
@@ -28,6 +30,10 @@ a {
2830

2931
.upload-button {
3032
margin-top: 6px !important;
33+
34+
&.error {
35+
border: 2px solid colors.$error-color;
36+
}
3137
}
3238

3339
.spinner {

alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
33
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
44
import { createMock, DeepMocked } from '@golevelup/ts-jest';
55
import { ApplicationDecisionV2Service } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.service';
6+
import { ToastService } from '../../../../../../services/toast/toast.service';
67

78
import { DecisionDocumentUploadDialogComponent } from './decision-document-upload-dialog.component';
89

@@ -31,6 +32,7 @@ describe('DecisionDocumentUploadDialogComponent', () => {
3132
},
3233
{ provide: MatDialogRef, useValue: mockDialogRef },
3334
{ provide: MAT_DIALOG_DATA, useValue: {} },
35+
{ provide: ToastService, useValue: {} },
3436
],
3537
imports: [MatDialogModule],
3638
schemas: [NO_ERRORS_SCHEMA],

alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { HttpErrorResponse } from '@angular/common/http';
12
import { Component, Inject, OnInit } from '@angular/core';
23
import { FormControl, FormGroup, Validators } from '@angular/forms';
34
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
45
import { ApplicationDecisionDocumentDto } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.dto';
56
import { ApplicationDecisionV2Service } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.service';
7+
import { ToastService } from '../../../../../../services/toast/toast.service';
68
import { DOCUMENT_SOURCE } from '../../../../../../shared/document/document.dto';
79

810
@Component({
@@ -36,12 +38,14 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
3638

3739
pendingFile: File | undefined;
3840
existingFile: string | undefined;
41+
showVirusError = false;
3942

4043
constructor(
4144
@Inject(MAT_DIALOG_DATA)
4245
public data: { fileId: string; decisionUuid: string; existingDocument?: ApplicationDecisionDocumentDto },
4346
protected dialog: MatDialogRef<any>,
44-
private decisionService: ApplicationDecisionV2Service
47+
private decisionService: ApplicationDecisionV2Service,
48+
private toastService: ToastService
4549
) {}
4650

4751
ngOnInit(): void {
@@ -63,7 +67,18 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
6367
if (this.data.existingDocument) {
6468
await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid);
6569
}
66-
await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile);
70+
71+
try {
72+
await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile);
73+
} catch (err) {
74+
this.toastService.showErrorToast('Document upload failed');
75+
if (err instanceof HttpErrorResponse && err.status === 403) {
76+
this.showVirusError = true;
77+
this.isSaving = false;
78+
this.pendingFile = undefined;
79+
return;
80+
}
81+
}
6782

6883
this.dialog.close(true);
6984
this.isSaving = false;
@@ -82,6 +97,7 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
8297
if (selectedFiles && selectedFiles[0]) {
8398
this.pendingFile = selectedFiles[0];
8499
this.name.setValue(selectedFiles[0].name);
100+
this.showVirusError = false;
85101
}
86102
}
87103

alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.html

+11-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ <h4>{{ title }} Document</h4>
1212
</div>
1313
<input hidden type="file" #fileInput (change)="uploadFile($event)" placeholder="Upload file" />
1414
<button
15+
*ngIf="!pendingFile && !existingFile"
1516
class="full-width upload-button"
1617
mat-flat-button
1718
color="accent"
18-
*ngIf="!pendingFile && !existingFile"
19+
[ngClass]="{
20+
error: showVirusError
21+
}"
1922
(click)="fileInput.click()"
2023
>
2124
Upload
@@ -26,7 +29,8 @@ <h4>{{ title }} Document</h4>
2629
&nbsp;({{ pendingFile.size | filesize }})
2730
</div>
2831
<button [disabled]="!allowsFileEdit" (click)="onRemoveFile()" mat-button>
29-
<mat-icon>close</mat-icon>Remove
32+
<mat-icon>close</mat-icon>
33+
Remove
3034
</button>
3135
</div>
3236
<div class="file" *ngIf="existingFile">
@@ -35,9 +39,13 @@ <h4>{{ title }} Document</h4>
3539
&nbsp;({{ existingFile.size | filesize }})
3640
</div>
3741
<button [disabled]="!allowsFileEdit" (click)="onRemoveFile()" mat-button>
38-
<mat-icon>close</mat-icon>Remove
42+
<mat-icon>close</mat-icon>
43+
Remove
3944
</button>
4045
</div>
46+
<mat-error class="left" style="display: flex" *ngIf="showVirusError">
47+
<mat-icon>warning</mat-icon>&nbsp;A virus was detected in the file. Choose another file and try again.
48+
</mat-error>
4149
</div>
4250

4351
<div class="double">

alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.scss

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ a {
3030

3131
.upload-button {
3232
margin-top: 6px !important;
33+
34+
&.error {
35+
border: 2px solid colors.$error-color;
36+
}
3337
}
3438

3539
.spinner {

alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest';
55
import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service';
66
import { ApplicationParcelService } from '../../../../services/application/application-parcel/application-parcel.service';
77
import { ApplicationSubmissionService } from '../../../../services/application/application-submission/application-submission.service';
8+
import { ToastService } from '../../../../services/toast/toast.service';
89

910
import { DocumentUploadDialogComponent } from './document-upload-dialog.component';
1011

@@ -45,6 +46,7 @@ describe('DocumentUploadDialogComponent', () => {
4546
},
4647
{ provide: MatDialogRef, useValue: mockDialogRef },
4748
{ provide: MAT_DIALOG_DATA, useValue: {} },
49+
{ provide: ToastService, useValue: {} },
4850
],
4951
imports: [MatDialogModule],
5052
schemas: [NO_ERRORS_SCHEMA],

alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.ts

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { HttpErrorResponse } from '@angular/common/http';
12
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
23
import { FormControl, FormGroup, Validators } from '@angular/forms';
34
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
@@ -9,6 +10,7 @@ import {
910
import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service';
1011
import { ApplicationParcelService } from '../../../../services/application/application-parcel/application-parcel.service';
1112
import { ApplicationSubmissionService } from '../../../../services/application/application-submission/application-submission.service';
13+
import { ToastService } from '../../../../services/toast/toast.service';
1214
import {
1315
DOCUMENT_SOURCE,
1416
DOCUMENT_SYSTEM,
@@ -59,14 +61,16 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy {
5961
pendingFile: File | undefined;
6062
existingFile: { name: string; size: number } | undefined;
6163
showSupersededWarning = false;
64+
showVirusError = false;
6265

6366
constructor(
6467
@Inject(MAT_DIALOG_DATA)
6568
public data: { fileId: string; existingDocument?: ApplicationDocumentDto },
6669
protected dialog: MatDialogRef<any>,
6770
private applicationDocumentService: ApplicationDocumentService,
6871
private parcelService: ApplicationParcelService,
69-
private submissionService: ApplicationSubmissionService
72+
private submissionService: ApplicationSubmissionService,
73+
private toastService: ToastService
7074
) {}
7175

7276
ngOnInit(): void {
@@ -126,11 +130,23 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy {
126130
if (this.data.existingDocument) {
127131
await this.applicationDocumentService.update(this.data.existingDocument.uuid, dto);
128132
} else if (file !== undefined) {
129-
await this.applicationDocumentService.upload(this.data.fileId, {
130-
...dto,
131-
file,
132-
});
133+
try {
134+
await this.applicationDocumentService.upload(this.data.fileId, {
135+
...dto,
136+
file,
137+
});
138+
} catch (err) {
139+
this.toastService.showErrorToast('Document upload failed');
140+
if (err instanceof HttpErrorResponse && err.status === 403) {
141+
this.showVirusError = true;
142+
this.isSaving = false;
143+
this.pendingFile = undefined;
144+
return;
145+
}
146+
}
147+
this.showVirusError = false;
133148
}
149+
134150
this.dialog.close(true);
135151
this.isSaving = false;
136152
}
@@ -228,6 +244,7 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy {
228244
if (selectedFiles && selectedFiles[0]) {
229245
this.pendingFile = selectedFiles[0];
230246
this.name.setValue(selectedFiles[0].name);
247+
this.showVirusError = false;
231248
}
232249
}
233250

alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ <h4>{{ title }} Document</h4>
99
</div>
1010
<input hidden type="file" #fileInput (change)="uploadFile($event)" placeholder="Upload file" />
1111
<button
12+
*ngIf="!pendingFile && !existingFile"
1213
class="full-width upload-button"
1314
mat-flat-button
1415
color="accent"
15-
*ngIf="!pendingFile && !existingFile"
16+
[ngClass]="{
17+
error: showVirusError
18+
}"
1619
(click)="fileInput.click()"
1720
>
1821
Upload
@@ -34,6 +37,9 @@ <h4>{{ title }} Document</h4>
3437
<mat-icon>close</mat-icon>Remove
3538
</button>
3639
</div>
40+
<mat-error class="left" style="display: flex" *ngIf="showVirusError">
41+
<mat-icon>warning</mat-icon>&nbsp;A virus was detected in the file. Choose another file and try again.
42+
</mat-error>
3743
</div>
3844

3945
<div class="double">

alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use '../../../../../../../styles/colors';
2+
13
.form {
24
display: grid;
35
grid-template-columns: 1fr 1fr;
@@ -28,6 +30,10 @@ a {
2830

2931
.upload-button {
3032
margin-top: 6px !important;
33+
34+
&.error {
35+
border: 2px solid colors.$error-color;
36+
}
3137
}
3238

3339
.spinner {

alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
33
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
44
import { createMock, DeepMocked } from '@golevelup/ts-jest';
55
import { NoticeOfIntentDecisionV2Service } from '../../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision-v2.service';
6+
import { ToastService } from '../../../../../../services/toast/toast.service';
67

78
import { DecisionDocumentUploadDialogComponent } from './decision-document-upload-dialog.component';
89

@@ -31,6 +32,7 @@ describe('DecisionDocumentUploadDialogComponent', () => {
3132
},
3233
{ provide: MatDialogRef, useValue: mockDialogRef },
3334
{ provide: MAT_DIALOG_DATA, useValue: {} },
35+
{ provide: ToastService, useValue: {} },
3436
],
3537
imports: [MatDialogModule],
3638
schemas: [NO_ERRORS_SCHEMA],

alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { HttpErrorResponse } from '@angular/common/http';
12
import { Component, Inject, OnInit } from '@angular/core';
23
import { FormControl, FormGroup, Validators } from '@angular/forms';
34
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
45
import { NoticeOfIntentDecisionV2Service } from '../../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision-v2.service';
56
import { NoticeOfIntentDecisionDocumentDto } from '../../../../../../services/notice-of-intent/decision/notice-of-intent-decision.dto';
7+
import { ToastService } from '../../../../../../services/toast/toast.service';
68
import { DOCUMENT_SOURCE } from '../../../../../../shared/document/document.dto';
79

810
@Component({
@@ -36,12 +38,14 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
3638

3739
pendingFile: File | undefined;
3840
existingFile: string | undefined;
41+
showVirusError = false;
3942

4043
constructor(
4144
@Inject(MAT_DIALOG_DATA)
4245
public data: { fileId: string; decisionUuid: string; existingDocument?: NoticeOfIntentDecisionDocumentDto },
4346
protected dialog: MatDialogRef<any>,
44-
private decisionService: NoticeOfIntentDecisionV2Service
47+
private decisionService: NoticeOfIntentDecisionV2Service,
48+
private toastService: ToastService
4549
) {}
4650

4751
ngOnInit(): void {
@@ -65,6 +69,18 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
6569
}
6670
await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile);
6771

72+
try {
73+
await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile);
74+
} catch (err) {
75+
this.toastService.showErrorToast('Document upload failed');
76+
if (err instanceof HttpErrorResponse && err.status === 403) {
77+
this.showVirusError = true;
78+
this.isSaving = false;
79+
this.pendingFile = undefined;
80+
return;
81+
}
82+
}
83+
6884
this.dialog.close(true);
6985
this.isSaving = false;
7086
} else if (this.data.existingDocument) {
@@ -82,6 +98,7 @@ export class DecisionDocumentUploadDialogComponent implements OnInit {
8298
if (selectedFiles && selectedFiles[0]) {
8399
this.pendingFile = selectedFiles[0];
84100
this.name.setValue(selectedFiles[0].name);
101+
this.showVirusError = false;
85102
}
86103
}
87104

alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ <h4>{{ title }} Document</h4>
1212
</div>
1313
<input hidden type="file" #fileInput (change)="uploadFile($event)" placeholder="Upload file" />
1414
<button
15+
*ngIf="!pendingFile && !existingFile"
1516
class="full-width upload-button"
1617
mat-flat-button
1718
color="accent"
18-
*ngIf="!pendingFile && !existingFile"
19+
[ngClass]="{
20+
error: showVirusError
21+
}"
1922
(click)="fileInput.click()"
2023
>
2124
Upload
@@ -38,6 +41,9 @@ <h4>{{ title }} Document</h4>
3841
<mat-icon>close</mat-icon>Remove
3942
</button>
4043
</div>
44+
<mat-error class="left" style="display: flex" *ngIf="showVirusError">
45+
<mat-icon>warning</mat-icon>&nbsp;A virus was detected in the file. Choose another file and try again.
46+
</mat-error>
4147
</div>
4248

4349
<div class="double">

alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.scss

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ a {
3030

3131
.upload-button {
3232
margin-top: 6px !important;
33+
34+
&.error {
35+
border: 2px solid colors.$error-color;
36+
}
3337
}
3438

3539
.spinner {

0 commit comments

Comments
 (0)