diff --git a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.html index 3e179f7cd..3d4c0df44 100644 --- a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.html @@ -83,4 +83,10 @@ - + diff --git a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.ts index 98decd5b7..3a270ea0b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen.component.ts @@ -11,6 +11,8 @@ import { placeholdersDescriptionsTranslations } from '../../translations/placeholders-descriptions-translations'; import { removeBraces } from '../../../../utils/functions'; +import { Toaster } from '../../../../services/toaster.service'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; interface Placeholder { placeholder: string; @@ -37,6 +39,7 @@ export class ReportsScreenComponent implements OnInit { private readonly _appStateService: AppStateService, private readonly _reportTemplateService: ReportTemplateControllerService, private readonly _dialogService: AdminDialogService, + private readonly _toaster: Toaster, private readonly _loadingService: LoadingService, readonly permissionsService: PermissionsService ) { @@ -81,9 +84,17 @@ export class ReportsScreenComponent implements OnInit { private async _uploadTemplate($event) { const file = $event.target.files[0]; - await this._reportTemplateService.uploadTemplateForm(this._appStateService.activeDossierTemplateId, file).toPromise(); - this._fileInput.nativeElement.value = null; - await this._loadReportTemplates(); + + if (this._isValidFile(file)) { + await this._reportTemplateService.uploadTemplateForm(this._appStateService.activeDossierTemplateId, false, file).toPromise(); + if (this._isExcelFile(file)) { + // await this._reportTemplateService.uploadTemplateForm(this._appStateService.activeDossierTemplateId, true, file).toPromise(); + } + this._fileInput.nativeElement.value = null; + await this._loadReportTemplates(); + } else { + this._toaster.error(_('reports-screen.invalid-upload')); + } } private async _deleteTemplate(template: ReportTemplate) { @@ -109,4 +120,22 @@ export class ReportsScreenComponent implements OnInit { })) ); } + + private _isValidFile(file: File): boolean { + return this._isExcelFile(file) || this._isWordFile(file); + } + + private _isExcelFile(file: File): boolean { + return ( + file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || + file.name.toLowerCase().endsWith('.xlsx') + ); + } + + private _isWordFile(file: File): boolean { + return ( + file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || + file.name.toLowerCase().endsWith('.docx') + ); + } } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 19f8ecc86..69bec7dda 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -1192,6 +1192,7 @@ }, "reports": "Reports", "reports-screen": { + "invalid-upload": "Invalid format selected for Upload! Supported formats are XLSX and DOCX", "description": "A short text explaining how to create report documents. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.", "descriptions": { "dossier-attributes": "This placeholder gets replaced with the value of the dossier attribute {attribute}.", diff --git a/libs/red-ui-http/src/lib/api/reportTemplateController.service.ts b/libs/red-ui-http/src/lib/api/reportTemplateController.service.ts index 53883c656..89726077f 100644 --- a/libs/red-ui-http/src/lib/api/reportTemplateController.service.ts +++ b/libs/red-ui-http/src/lib/api/reportTemplateController.service.ts @@ -16,17 +16,17 @@ import { CustomHttpUrlEncodingCodec } from '../encoder'; import { Observable } from 'rxjs'; +import { PlaceholdersResponse } from '../model/placeholdersResponse'; import { ReportTemplate } from '../model/reportTemplate'; import { BASE_PATH } from '../variables'; import { Configuration } from '../configuration'; -import { PlaceholdersResponse } from '../model/placeholdersResponse'; @Injectable() export class ReportTemplateControllerService { + protected basePath = ''; public defaultHeaders = new HttpHeaders(); public configuration = new Configuration(); - protected basePath = ''; constructor( protected httpClient: HttpClient, @@ -42,6 +42,151 @@ export class ReportTemplateControllerService { } } + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Delete template file for redaction-report + * None + * @param dossierTemplateId dossierTemplateId + * @param templateId templateId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public deleteTemplate(dossierTemplateId: string, templateId: string, observe?: 'body', reportProgress?: boolean): Observable; + public deleteTemplate( + dossierTemplateId: string, + templateId: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public deleteTemplate( + dossierTemplateId: string, + templateId: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public deleteTemplate( + dossierTemplateId: string, + templateId: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (dossierTemplateId === null || dossierTemplateId === undefined) { + throw new Error('Required parameter dossierTemplateId was null or undefined when calling deleteTemplate.'); + } + + if (templateId === null || templateId === undefined) { + throw new Error('Required parameter templateId was null or undefined when calling deleteTemplate.'); + } + + let headers = this.defaultHeaders; + + // authentication (RED-OAUTH) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + return this.httpClient.request( + 'delete', + `${this.basePath}/templateUpload/${encodeURIComponent(String(dossierTemplateId))}/${encodeURIComponent(String(templateId))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Download template file for redaction-report + * None + * @param dossierTemplateId dossierTemplateId + * @param templateId templateId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public downloadReportTemplate( + dossierTemplateId: string, + templateId: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public downloadReportTemplate( + dossierTemplateId: string, + templateId: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public downloadReportTemplate( + dossierTemplateId: string, + templateId: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public downloadReportTemplate( + dossierTemplateId: string, + templateId: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (dossierTemplateId === null || dossierTemplateId === undefined) { + throw new Error('Required parameter dossierTemplateId was null or undefined when calling downloadReportTemplate.'); + } + + if (templateId === null || templateId === undefined) { + throw new Error('Required parameter templateId was null or undefined when calling downloadReportTemplate.'); + } + + let headers = this.defaultHeaders; + + // authentication (RED-OAUTH) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + return this.httpClient.request( + 'get', + `${this.basePath}/templateUpload/${encodeURIComponent(String(dossierTemplateId))}/${encodeURIComponent(String(templateId))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * Returns list of available placeholders * None @@ -97,144 +242,6 @@ export class ReportTemplateControllerService { ); } - /** - * Delete template file for redaction-report - * None - * @param dossierTemplateId dossierTemplateId - * @param templateId templateId - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public deleteTemplate(dossierTemplateId: string, templateId: string, observe?: 'body', reportProgress?: boolean): Observable; - - public deleteTemplate( - dossierTemplateId: string, - templateId: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - - public deleteTemplate( - dossierTemplateId: string, - templateId: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - - public deleteTemplate( - dossierTemplateId: string, - templateId: string, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - if (dossierTemplateId === null || dossierTemplateId === undefined) { - throw new Error('Required parameter dossierTemplateId was null or undefined when calling deleteTemplate.'); - } - - if (templateId === null || templateId === undefined) { - throw new Error('Required parameter templateId was null or undefined when calling deleteTemplate.'); - } - - let headers = this.defaultHeaders; - - // authentication (RED-OAUTH) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected !== undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - return this.httpClient.request( - 'delete', - `${this.basePath}/templateUpload/${encodeURIComponent(String(dossierTemplateId))}/${encodeURIComponent(String(templateId))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Download template file for redaction-report - * None - * @param dossierTemplateId dossierTemplateId - * @param templateId templateId - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public downloadReportTemplate( - dossierTemplateId: string, - templateId: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - - public downloadReportTemplate( - dossierTemplateId: string, - templateId: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - - public downloadReportTemplate( - dossierTemplateId: string, - templateId: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - - public downloadReportTemplate( - dossierTemplateId: string, - templateId: string, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - if (dossierTemplateId === null || dossierTemplateId === undefined) { - throw new Error('Required parameter dossierTemplateId was null or undefined when calling downloadReportTemplate.'); - } - - if (templateId === null || templateId === undefined) { - throw new Error('Required parameter templateId was null or undefined when calling downloadReportTemplate.'); - } - - let headers = this.defaultHeaders; - - // authentication (RED-OAUTH) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected !== undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - return this.httpClient.request( - 'get', - `${this.basePath}/templateUpload/${encodeURIComponent(String(dossierTemplateId))}/${encodeURIComponent(String(templateId))}`, - { - withCredentials: this.configuration.withCredentials, - responseType: 'blob', - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - /** * Returns available templates for redaction-report * None @@ -247,19 +254,16 @@ export class ReportTemplateControllerService { observe?: 'body', reportProgress?: boolean ): Observable>; - public getAvailableReportTemplates( dossierTemplateId: string, observe?: 'response', reportProgress?: boolean ): Observable>>; - public getAvailableReportTemplates( dossierTemplateId: string, observe?: 'events', reportProgress?: boolean ): Observable>>; - public getAvailableReportTemplates(dossierTemplateId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierTemplateId === null || dossierTemplateId === undefined) { throw new Error('Required parameter dossierTemplateId was null or undefined when calling getAvailableReportTemplates.'); @@ -297,33 +301,35 @@ export class ReportTemplateControllerService { * Upload template file for redaction-report * None * @param dossierTemplateId The dossierTemplateId, the report template belongs to + * @param multiFileReport * @param file * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ public uploadTemplateForm( dossierTemplateId: string, + multiFileReport?: boolean, file?: Blob, observe?: 'body', reportProgress?: boolean ): Observable; - public uploadTemplateForm( dossierTemplateId: string, + multiFileReport?: boolean, file?: Blob, observe?: 'response', reportProgress?: boolean ): Observable>; - public uploadTemplateForm( dossierTemplateId: string, + multiFileReport?: boolean, file?: Blob, observe?: 'events', reportProgress?: boolean ): Observable>; - public uploadTemplateForm( dossierTemplateId: string, + multiFileReport?: boolean, file?: Blob, observe: any = 'body', reportProgress: boolean = false @@ -365,6 +371,9 @@ export class ReportTemplateControllerService { formParams = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); } + if (multiFileReport !== undefined) { + formParams = (formParams.append('multiFileReport', multiFileReport) as any) || formParams; + } if (file !== undefined) { formParams = (formParams.append('file', file) as any) || formParams; } @@ -381,18 +390,4 @@ export class ReportTemplateControllerService { } ); } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } } diff --git a/libs/red-ui-http/src/lib/model/notification.ts b/libs/red-ui-http/src/lib/model/notification.ts index db999aeb3..0da921221 100644 --- a/libs/red-ui-http/src/lib/model/notification.ts +++ b/libs/red-ui-http/src/lib/model/notification.ts @@ -18,6 +18,6 @@ export interface Notification { readDate?: string; seenDate?: string; softDeleted?: string; - target?: any; + target?: string; userId?: string; } diff --git a/libs/red-ui-http/src/lib/model/reportTemplate.ts b/libs/red-ui-http/src/lib/model/reportTemplate.ts index 1490ce0b0..6271c26c4 100644 --- a/libs/red-ui-http/src/lib/model/reportTemplate.ts +++ b/libs/red-ui-http/src/lib/model/reportTemplate.ts @@ -13,6 +13,7 @@ export interface ReportTemplate { dossierTemplateId?: string; fileName?: string; + multiFileReport?: boolean; storageId?: string; templateId?: string; uploadDate?: string;