Pull request #365: VM/RED-3982
Merge in RED/ui from VM/RED-3982 to master * commit 'f888d59a660892e6f8759faf513c1117f969f8fa': RED-3982 - used 'DetailsRadioComponent' to choose between kms and pkcs configurations RED-3982 - updates to be able to edit/delete digital signature RED-3982 - changes to can update digital signature RED-3982 - fixed some imports RED-3982 - updates to add 'pkcs signature' and 'kms signature' forms also on main screen component to be edited RED-3982 - added 'pkcs signature' and 'kms signature' forms RED-3982 - extracted upload file logic from import redactions dialog component into a separate component to be reusable also for certificate configuration RED-3982 - WIP on 'Configure Digital Signature Certificate' dialog
This commit is contained in:
commit
37ed602cba
@ -43,6 +43,9 @@ import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-dele
|
||||
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
|
||||
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||
import { SystemPreferencesFormComponent } from './screens/general-config/system-preferences-form/system-preferences-form.component';
|
||||
import { ConfigureCertificateDialogComponent } from './dialogs/configure-digital-signature-dialog/configure-certificate-dialog.component';
|
||||
import { PkcsSignatureConfigurationComponent } from './dialogs/configure-digital-signature-dialog/form/pkcs-signature-configuration/pkcs-signature-configuration.component';
|
||||
import { KmsSignatureConfigurationComponent } from './dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component';
|
||||
|
||||
const dialogs = [
|
||||
AddEditCloneDossierTemplateDialogComponent,
|
||||
@ -57,6 +60,7 @@ const dialogs = [
|
||||
UploadDictionaryDialogComponent,
|
||||
AddEditDossierStateDialogComponent,
|
||||
ConfirmDeleteDossierStateDialogComponent,
|
||||
ConfigureCertificateDialogComponent,
|
||||
];
|
||||
|
||||
const screens = [
|
||||
@ -84,6 +88,8 @@ const components = [
|
||||
GeneralConfigFormComponent,
|
||||
SmtpFormComponent,
|
||||
SystemPreferencesFormComponent,
|
||||
PkcsSignatureConfigurationComponent,
|
||||
KmsSignatureConfigurationComponent,
|
||||
|
||||
...dialogs,
|
||||
...screens,
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
<section class="dialog">
|
||||
<div
|
||||
class="dialog-header heading-l"
|
||||
[translate]="!isInConfiguration ? translations.title.beforeConfiguration : translations.title[selectedOption]"
|
||||
></div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<form [formGroup]="form" *ngIf="!isInConfiguration">
|
||||
<iqser-details-radio [options]="options" formControlName="option"></iqser-details-radio>
|
||||
</form>
|
||||
<ng-container *ngIf="isInConfiguration">
|
||||
{{ 'digital-signature-dialog.upload-warning-message' | translate }}
|
||||
|
||||
<redaction-pkcs-signature-configuration
|
||||
*ngIf="selectedOption === digitalSignatureOptions.PKCS"
|
||||
></redaction-pkcs-signature-configuration>
|
||||
<redaction-kms-signature-configuration
|
||||
*ngIf="selectedOption === digitalSignatureOptions.KMS"
|
||||
></redaction-kms-signature-configuration>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<ng-container *ngIf="!isInConfiguration">
|
||||
<button (click)="toggleIsInConfiguration()" color="primary" mat-flat-button>
|
||||
{{ 'digital-signature-dialog.actions.continue' | translate }}
|
||||
</button>
|
||||
<div translate="digital-signature-dialog.actions.cancel" class="all-caps-label cancel" mat-dialog-close></div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isInConfiguration">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
{{ 'digital-signature-dialog.actions.save' | translate }}
|
||||
</button>
|
||||
<div translate="digital-signature-dialog.actions.back" class="all-caps-label cancel" (click)="toggleIsInConfiguration()"></div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,37 @@
|
||||
@use 'variables';
|
||||
|
||||
.dialog {
|
||||
.dialog-content {
|
||||
.option {
|
||||
margin-top: 12px;
|
||||
height: 56px;
|
||||
border-radius: 8px;
|
||||
background: rgba(variables.$grey-2, 0.8);
|
||||
border: 16px solid transparent;
|
||||
cursor: pointer;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
|
||||
iqser-round-checkbox {
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.description {
|
||||
font-size: 11px;
|
||||
opacity: 0.7;
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
background: rgba(variables.$red-1, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
import { ChangeDetectorRef, Component, Injector, ViewChild } from '@angular/core';
|
||||
import { digitalSignatureDialogTranslations } from '../../translations/digital-signature-dialog-translations';
|
||||
import { BaseDialogComponent, DetailsRadioOption, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { PkcsSignatureConfigurationComponent } from './form/pkcs-signature-configuration/pkcs-signature-configuration.component';
|
||||
import { KmsSignatureConfigurationComponent } from './form/kms-signature-configuration/kms-signature-configuration.component';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { HttpStatusCode } from '@angular/common/http';
|
||||
import { DigitalSignatureOption, DigitalSignatureOptions } from '@red/domain';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
const DEFAULT_DIALOG_WIDTH = '662px';
|
||||
const KMS_SIGNATURE_DIALOG_WIDTH = '810px';
|
||||
|
||||
@Component({
|
||||
templateUrl: './configure-certificate-dialog.component.html',
|
||||
styleUrls: ['./configure-certificate-dialog.component.scss'],
|
||||
})
|
||||
export class ConfigureCertificateDialogComponent extends BaseDialogComponent {
|
||||
@ViewChild(PkcsSignatureConfigurationComponent) pkcsSignatureConfigurationComponent: PkcsSignatureConfigurationComponent;
|
||||
@ViewChild(KmsSignatureConfigurationComponent) kmsSignatureConfigurationComponent: KmsSignatureConfigurationComponent;
|
||||
|
||||
readonly digitalSignatureOptions = DigitalSignatureOptions;
|
||||
readonly translations = digitalSignatureDialogTranslations;
|
||||
readonly options: DetailsRadioOption<DigitalSignatureOption>[] = [
|
||||
{
|
||||
label: _('digital-signature-dialog.options.pkcs.label'),
|
||||
value: DigitalSignatureOptions.PKCS,
|
||||
description: _('digital-signature-dialog.options.pkcs.description'),
|
||||
},
|
||||
{
|
||||
label: _('digital-signature-dialog.options.kms.label'),
|
||||
value: DigitalSignatureOptions.KMS,
|
||||
description: _('digital-signature-dialog.options.kms.description'),
|
||||
},
|
||||
];
|
||||
|
||||
isInConfiguration = false;
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<ConfigureCertificateDialogComponent>,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
) {
|
||||
super(_injector, _dialogRef);
|
||||
|
||||
this.form = this._formBuilder.group({
|
||||
option: [this.options[0]],
|
||||
});
|
||||
}
|
||||
|
||||
toggleIsInConfiguration() {
|
||||
this.isInConfiguration = !this.isInConfiguration;
|
||||
if (this.isInConfiguration && this.selectedOption === DigitalSignatureOptions.KMS) {
|
||||
this._dialogRef.updateSize(KMS_SIGNATURE_DIALOG_WIDTH);
|
||||
} else {
|
||||
this._dialogRef.updateSize(DEFAULT_DIALOG_WIDTH);
|
||||
}
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
get disabled(): boolean {
|
||||
return this.activeComponent?.disabled;
|
||||
}
|
||||
|
||||
get activeComponent() {
|
||||
return this.selectedOption === DigitalSignatureOptions.PKCS
|
||||
? this.pkcsSignatureConfigurationComponent
|
||||
: this.kmsSignatureConfigurationComponent;
|
||||
}
|
||||
|
||||
get selectedOption(): DigitalSignatureOption {
|
||||
return this.form.get('option').value.value;
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
try {
|
||||
await this.activeComponent.save();
|
||||
this._toaster.success(_('digital-signature-dialog.actions.save-success'));
|
||||
this._dialogRef.close(true);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (error.status === HttpStatusCode.BadRequest) {
|
||||
this._toaster.error(_('digital-signature-dialog.actions.certificate-not-valid-error'));
|
||||
} else {
|
||||
this._toaster.error(_('digital-signature-dialog.actions.save-error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
import { BaseFormComponent } from '@iqser/common-ui';
|
||||
import { DigitalSignatureService } from '../../../services/digital-signature.service';
|
||||
import { IDigitalSignatureRequest, DigitalSignatureOption, DigitalSignatureOptions } from '@red/domain';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
|
||||
export abstract class BaseSignatureConfigurationComponent extends BaseFormComponent {
|
||||
file: File | null;
|
||||
|
||||
protected constructor(
|
||||
protected readonly _digitalSignatureService: DigitalSignatureService,
|
||||
private readonly _selectedOption: DigitalSignatureOption,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
setCertificateName(file: File | null): void {
|
||||
if (file) {
|
||||
let name = file.name.split('.')[0];
|
||||
name = name.replace(/-/g, ' ');
|
||||
this.form.controls['certificateName'].setValue(name);
|
||||
} else {
|
||||
this.form.controls['certificateName'].setValue('');
|
||||
}
|
||||
}
|
||||
|
||||
generateFile(certificateName: string, extension: '.p12' | '.pem'): File | null {
|
||||
if (certificateName) {
|
||||
return {
|
||||
name: certificateName.split(' ').join('-') + extension,
|
||||
} as File;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
resetInitialFormValue(): void {
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
deleteSignature(): Promise<unknown> {
|
||||
const observable: Observable<unknown> =
|
||||
this._selectedOption === DigitalSignatureOptions.PKCS
|
||||
? this._digitalSignatureService.deleteSignature()
|
||||
: this._digitalSignatureService.deleteKmsSignature();
|
||||
return firstValueFrom(observable);
|
||||
}
|
||||
|
||||
abstract addRemoveCertificate(file: File | null): void;
|
||||
|
||||
abstract save(): Promise<IDigitalSignatureRequest | unknown>;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<iqser-upload-file [class.w-300]="!!file" accept=".pem" [file]="file" [readonly]="!!file" (fileChanged)="addRemoveCertificate($event)">
|
||||
</iqser-upload-file>
|
||||
<form [formGroup]="form">
|
||||
<div class="flex">
|
||||
<div class="flex fields-container">
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.kms.certificate-name"></label>
|
||||
<input formControlName="certificateName" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.kms.kms-service-endpoint"></label>
|
||||
<input formControlName="kmsServiceEndpoint" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.kms.kms-region"></label>
|
||||
<input formControlName="kmsRegion" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.kms.kms-id"></label>
|
||||
<input formControlName="kmsKeyId" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.kms.kms-access-key"></label>
|
||||
<input formControlName="kmsAccessKey" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300" *ngIf="!digitalSignature">
|
||||
<label translate="digital-signature-dialog.forms.kms.kms-secret-key"></label>
|
||||
<input formControlName="kmsSecretKey" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex fields-container" *ngIf="!digitalSignature">
|
||||
<div class="iqser-input-group required w-400 certificate">
|
||||
<label translate="digital-signature-dialog.forms.kms.certificate-content"></label>
|
||||
<textarea formControlName="certificate" type="text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,18 @@
|
||||
.certificate {
|
||||
height: 100%;
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.w-300 {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
iqser-upload-file {
|
||||
display: block;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { FormBuilder, Validators } from '@angular/forms';
|
||||
import { BaseSignatureConfigurationComponent } from '../base-signature-configuration-component';
|
||||
import { IKmsDigitalSignature, IKmsDigitalSignatureRequest, DigitalSignatureOptions } from '@red/domain';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DigitalSignatureService } from '../../../../services/digital-signature.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-kms-signature-configuration',
|
||||
templateUrl: './kms-signature-configuration.component.html',
|
||||
styleUrls: ['./kms-signature-configuration.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class KmsSignatureConfigurationComponent extends BaseSignatureConfigurationComponent implements OnInit {
|
||||
@Input() digitalSignature!: IKmsDigitalSignatureRequest;
|
||||
|
||||
constructor(protected readonly _digitalSignatureService: DigitalSignatureService, private readonly _formBuilder: FormBuilder) {
|
||||
super(_digitalSignatureService, DigitalSignatureOptions.KMS);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this._formBuilder.group({
|
||||
certificateName: [this.digitalSignature?.certificateName, Validators.required],
|
||||
kmsServiceEndpoint: [this.digitalSignature?.kmsServiceEndpoint, Validators.required],
|
||||
kmsRegion: [this.digitalSignature?.kmsRegion, Validators.required],
|
||||
kmsKeyId: [this.digitalSignature?.kmsKeyId, Validators.required],
|
||||
kmsAccessKey: [this.digitalSignature?.kmsAccessKey, Validators.required],
|
||||
kmsSecretKey: this.digitalSignature ? null : ['', Validators.required],
|
||||
certificate: this.digitalSignature ? null : ['', Validators.required],
|
||||
});
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this.file = this.generateFile(this.digitalSignature?.certificateName, '.pem');
|
||||
}
|
||||
|
||||
addRemoveCertificate(file: File | null): void {
|
||||
this.setCertificateName(file);
|
||||
if (file) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => {
|
||||
const binaryContent = <string>fileReader.result;
|
||||
this.form.get('certificate').setValue(binaryContent);
|
||||
};
|
||||
fileReader.readAsBinaryString(file as Blob);
|
||||
} else {
|
||||
this.form.controls['certificate'].setValue('');
|
||||
}
|
||||
}
|
||||
|
||||
save(): Promise<IKmsDigitalSignatureRequest> {
|
||||
const formValue = this.form.getRawValue();
|
||||
const digitalSignature: IKmsDigitalSignature = { ...formValue };
|
||||
|
||||
if (!this.digitalSignature) {
|
||||
digitalSignature.certificate = window.btoa(<string>digitalSignature.certificate);
|
||||
}
|
||||
|
||||
return firstValueFrom(this._digitalSignatureService.saveKmsSignature(digitalSignature));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<iqser-upload-file
|
||||
[class.w-400]="!!file"
|
||||
accept=".p12"
|
||||
[file]="file"
|
||||
[readonly]="!!file"
|
||||
(fileChanged)="addRemoveCertificate($event)"
|
||||
></iqser-upload-file>
|
||||
<form [formGroup]="form">
|
||||
<div class="flex">
|
||||
<div class="flex fields-container">
|
||||
<div class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-dialog.forms.pkcs.certificate-name"></label>
|
||||
<input formControlName="certificateName" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group required w-300" *ngIf="!digitalSignature">
|
||||
<label translate="digital-signature-dialog.forms.pkcs.password-key"></label>
|
||||
<input formControlName="password" type="password" />
|
||||
</div>
|
||||
<div class="iqser-input-group w-300">
|
||||
<label translate="digital-signature-dialog.forms.pkcs.contact-information"></label>
|
||||
<input formControlName="contactInfo" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group w-300">
|
||||
<label translate="digital-signature-dialog.forms.pkcs.location"></label>
|
||||
<input formControlName="location" type="text" />
|
||||
</div>
|
||||
<div class="iqser-input-group w-450">
|
||||
<label translate="digital-signature-dialog.forms.pkcs.reason"></label>
|
||||
<textarea formControlName="reason" rows="4" type="text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,13 @@
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.w-400 {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
iqser-upload-file {
|
||||
display: block;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { FormBuilder, Validators } from '@angular/forms';
|
||||
import { BaseSignatureConfigurationComponent } from '../base-signature-configuration-component';
|
||||
import { IPkcsDigitalSignature, IPkcsDigitalSignatureRequest, DigitalSignatureOptions } from '@red/domain';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DigitalSignatureService } from '../../../../services/digital-signature.service';
|
||||
import { lastIndexOfEnd } from '../../../../../../utils';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-pkcs-signature-configuration',
|
||||
templateUrl: './pkcs-signature-configuration.component.html',
|
||||
styleUrls: ['./pkcs-signature-configuration.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PkcsSignatureConfigurationComponent extends BaseSignatureConfigurationComponent implements OnInit {
|
||||
@Input() digitalSignature!: IPkcsDigitalSignatureRequest;
|
||||
|
||||
constructor(protected readonly _digitalSignatureService: DigitalSignatureService, private readonly _formBuilder: FormBuilder) {
|
||||
super(_digitalSignatureService, DigitalSignatureOptions.PKCS);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this._formBuilder.group({
|
||||
certificateName: [this.digitalSignature?.certificateName, Validators.required],
|
||||
password: this.digitalSignature ? null : ['', Validators.required],
|
||||
contactInfo: [this.digitalSignature?.contactInfo],
|
||||
location: [this.digitalSignature?.location],
|
||||
reason: [this.digitalSignature?.reason],
|
||||
base64EncodedPrivateKey: this.digitalSignature ? null : ['', Validators.required],
|
||||
});
|
||||
this.resetInitialFormValue();
|
||||
this.file = this.generateFile(this.digitalSignature?.certificateName, '.p12');
|
||||
}
|
||||
|
||||
addRemoveCertificate(file: File | null): void {
|
||||
this.setCertificateName(file);
|
||||
if (file) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => {
|
||||
const dataUrl = <string>fileReader.result;
|
||||
const actualBase64Value = dataUrl.substring(lastIndexOfEnd(dataUrl, ';base64,'));
|
||||
this.form.get('base64EncodedPrivateKey').setValue(actualBase64Value);
|
||||
};
|
||||
fileReader.readAsDataURL(file as Blob);
|
||||
} else {
|
||||
this.form.controls['base64EncodedPrivateKey'].setValue('');
|
||||
}
|
||||
}
|
||||
|
||||
save(): Promise<IPkcsDigitalSignatureRequest | unknown> {
|
||||
const formValue = this.form.getRawValue();
|
||||
const digitalSignature: IPkcsDigitalSignature = { ...formValue };
|
||||
|
||||
const observable = this.digitalSignature
|
||||
? this._digitalSignatureService.updateSignature(digitalSignature)
|
||||
: this._digitalSignatureService.saveSignature(digitalSignature);
|
||||
return firstValueFrom(observable);
|
||||
}
|
||||
}
|
||||
@ -13,91 +13,42 @@
|
||||
<div class="content-inner">
|
||||
<div class="content-container">
|
||||
<div class="content-container-content">
|
||||
<form *ngIf="form" [formGroup]="form" autocomplete="off">
|
||||
<input #fileInput (change)="fileChanged($event, fileInput)" class="file-upload-input" hidden type="file" />
|
||||
<iqser-empty-state
|
||||
(action)="openConfigureCertificate()"
|
||||
*ngIf="!digitalSignature"
|
||||
[buttonLabel]="'digital-signature-screen.no-data.action' | translate"
|
||||
[text]="'digital-signature-screen.no-data.title' | translate"
|
||||
icon="iqser:document"
|
||||
[buttonIcon]="null"
|
||||
></iqser-empty-state>
|
||||
|
||||
<iqser-empty-state
|
||||
(action)="fileInput.click()"
|
||||
*ngIf="!hasDigitalSignatureSet"
|
||||
[buttonLabel]="'digital-signature-screen.no-data.action' | translate"
|
||||
[text]="'digital-signature-screen.no-data.title' | translate"
|
||||
buttonIcon="iqser:upload"
|
||||
></iqser-empty-state>
|
||||
<ng-container *ngIf="digitalSignature">
|
||||
<redaction-pkcs-signature-configuration
|
||||
*ngIf="currentCertificateType === certificateType.PKCS"
|
||||
[digitalSignature]="digitalSignature"
|
||||
></redaction-pkcs-signature-configuration>
|
||||
<redaction-kms-signature-configuration
|
||||
*ngIf="currentCertificateType === certificateType.KMS"
|
||||
[digitalSignature]="digitalSignature"
|
||||
></redaction-kms-signature-configuration>
|
||||
</ng-container>
|
||||
|
||||
<div [class.hidden]="!hasDigitalSignatureSet" class="iqser-input-group required w-300">
|
||||
<label translate="digital-signature-screen.certificate-name.label"></label>
|
||||
<input
|
||||
[placeholder]="'digital-signature-screen.certificate-name.placeholder' | translate"
|
||||
formControlName="certificateName"
|
||||
name="certificateName"
|
||||
/>
|
||||
</div>
|
||||
<div [class.hidden]="!digitalSignature" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="saveDigitalSignature()"
|
||||
[disabled]="disabled"
|
||||
[label]="'digital-signature-screen.action.save' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
|
||||
<div
|
||||
*ngIf="!digitalSignatureExists"
|
||||
[class.hidden]="!hasDigitalSignatureSet"
|
||||
class="iqser-input-group required w-300"
|
||||
>
|
||||
<label translate="digital-signature-screen.password.label"></label>
|
||||
<input
|
||||
[placeholder]="'digital-signature-screen.password.placeholder' | translate"
|
||||
formControlName="keySecret"
|
||||
name="keySecret"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div [class.hidden]="!hasDigitalSignatureSet" class="iqser-input-group w-300">
|
||||
<label translate="digital-signature-screen.reason.label"></label>
|
||||
<input
|
||||
[placeholder]="'digital-signature-screen.reason.placeholder' | translate"
|
||||
formControlName="reason"
|
||||
name="reason"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div [class.hidden]="!hasDigitalSignatureSet" class="iqser-input-group w-300">
|
||||
<label translate="digital-signature-screen.location.label"></label>
|
||||
<input
|
||||
[placeholder]="'digital-signature-screen.location.placeholder' | translate"
|
||||
formControlName="location"
|
||||
name="location"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div [class.hidden]="!hasDigitalSignatureSet" class="iqser-input-group w-300">
|
||||
<label translate="digital-signature-screen.contact-info.label"></label>
|
||||
<input
|
||||
[placeholder]="'digital-signature-screen.contact-info.placeholder' | translate"
|
||||
formControlName="contactInfo"
|
||||
name="contactInfo"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div [class.hidden]="!hasDigitalSignatureSet" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="saveDigitalSignature()"
|
||||
[disabled]="form.invalid"
|
||||
[label]="'digital-signature-screen.action.save' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
|
||||
<iqser-icon-button
|
||||
(action)="removeDigitalSignature()"
|
||||
*ngIf="digitalSignatureExists"
|
||||
[label]="'digital-signature-screen.action.delete' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:trash"
|
||||
></iqser-icon-button>
|
||||
|
||||
<div
|
||||
(click)="loadDigitalSignatureAndInitializeForm()"
|
||||
*ngIf="!digitalSignatureExists"
|
||||
class="all-caps-label cancel"
|
||||
translate="digital-signature-screen.action.reset"
|
||||
></div>
|
||||
</div>
|
||||
</form>
|
||||
(click)="removeDigitalSignature()"
|
||||
*ngIf="digitalSignature"
|
||||
class="all-caps-label cancel"
|
||||
translate="digital-signature-screen.action.remove"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { lastIndexOfEnd } from '@utils/functions';
|
||||
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { DigitalSignatureService } from '../../services/digital-signature.service';
|
||||
import { IDigitalSignature } from '@red/domain';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { HttpStatusCode } from '@angular/common/http';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { PkcsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/pkcs-signature-configuration/pkcs-signature-configuration.component';
|
||||
import { KmsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component';
|
||||
import { DigitalSignatureOptions, IKmsDigitalSignatureRequest, IPkcsDigitalSignatureRequest } from '@red/domain';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-digital-signature-screen',
|
||||
@ -16,65 +16,34 @@ import { HttpStatusCode } from '@angular/common/http';
|
||||
styleUrls: ['./digital-signature-screen.component.scss'],
|
||||
})
|
||||
export class DigitalSignatureScreenComponent implements OnInit {
|
||||
@ViewChild(PkcsSignatureConfigurationComponent) pkcsSignatureConfigurationComponent: PkcsSignatureConfigurationComponent;
|
||||
@ViewChild(KmsSignatureConfigurationComponent) kmsSignatureConfigurationComponent: KmsSignatureConfigurationComponent;
|
||||
|
||||
readonly certificateType = DigitalSignatureOptions;
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
digitalSignature: IDigitalSignature;
|
||||
form: FormGroup;
|
||||
|
||||
digitalSignatureExists = false;
|
||||
digitalSignature: IPkcsDigitalSignatureRequest | IKmsDigitalSignatureRequest;
|
||||
|
||||
constructor(
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
readonly routerHistoryService: RouterHistoryService,
|
||||
private readonly _digitalSignatureService: DigitalSignatureService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
readonly routerHistoryService: RouterHistoryService,
|
||||
) {}
|
||||
|
||||
get hasDigitalSignatureSet() {
|
||||
return this.digitalSignatureExists || !!this.form.get('base64EncodedPrivateKey').value;
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.loadDigitalSignatureAndInitializeForm();
|
||||
}
|
||||
|
||||
async saveDigitalSignature(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const formValue = this.form.getRawValue();
|
||||
const digitalSignature: IDigitalSignature = {
|
||||
...formValue,
|
||||
};
|
||||
//adjusted for chrome auto-complete / password manager
|
||||
digitalSignature.password = formValue.keySecret;
|
||||
|
||||
const observable = this.digitalSignatureExists
|
||||
? this._digitalSignatureService.update(digitalSignature)
|
||||
: this._digitalSignatureService.save(digitalSignature);
|
||||
|
||||
try {
|
||||
await firstValueFrom(observable);
|
||||
await this.loadDigitalSignatureAndInitializeForm();
|
||||
this._toaster.success(_('digital-signature-screen.action.save-success'));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error.status === HttpStatusCode.BadRequest) {
|
||||
this._toaster.error(_('digital-signature-screen.action.certificate-not-valid-error'));
|
||||
} else {
|
||||
this._toaster.error(_('digital-signature-screen.action.save-error'));
|
||||
}
|
||||
}
|
||||
|
||||
this._loadingService.stop();
|
||||
await this.loadDigitalSignature();
|
||||
}
|
||||
|
||||
async removeDigitalSignature(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
try {
|
||||
await firstValueFrom(this._digitalSignatureService.delete());
|
||||
await this.loadDigitalSignatureAndInitializeForm();
|
||||
await this.activeComponent.deleteSignature();
|
||||
await this.loadDigitalSignature();
|
||||
this._toaster.success(_('digital-signature-screen.action.delete-success'));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@ -82,44 +51,47 @@ export class DigitalSignatureScreenComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
fileChanged(event, input: HTMLInputElement) {
|
||||
const file = event.target.files[0];
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => {
|
||||
const dataUrl = <string>fileReader.result;
|
||||
const actualBase64Value = dataUrl.substring(lastIndexOfEnd(dataUrl, ';base64,'));
|
||||
this.form.get('base64EncodedPrivateKey').setValue(actualBase64Value);
|
||||
this.form.get('certificateName').setValue(file.name);
|
||||
input.value = null;
|
||||
};
|
||||
fileReader.readAsDataURL(file as Blob);
|
||||
get disabled(): boolean {
|
||||
//TODO remove second check when the update endpoint will be available for KMS signature
|
||||
return this.activeComponent?.disabled || this.currentCertificateType === DigitalSignatureOptions.KMS;
|
||||
}
|
||||
|
||||
async loadDigitalSignatureAndInitializeForm(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
async saveDigitalSignature(): Promise<void> {
|
||||
try {
|
||||
const digitalSignature = await firstValueFrom(this._digitalSignatureService.getSignature());
|
||||
this.digitalSignatureExists = true;
|
||||
this.digitalSignature = digitalSignature;
|
||||
await this.activeComponent.save();
|
||||
this.activeComponent.resetInitialFormValue();
|
||||
this._toaster.success(_('digital-signature-screen.action.save-success'));
|
||||
} catch (error) {
|
||||
this.digitalSignatureExists = false;
|
||||
this.digitalSignature = {};
|
||||
this._toaster.error(_('digital-signature-screen.action.save-error'));
|
||||
}
|
||||
|
||||
this.form = this._getForm();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
private _getForm(): FormGroup {
|
||||
return this._formBuilder.group({
|
||||
certificateName: [this.digitalSignature.certificateName, Validators.required],
|
||||
contactInfo: this.digitalSignature.contactInfo,
|
||||
location: this.digitalSignature.location,
|
||||
keySecret: this.digitalSignatureExists ? null : [this.digitalSignature.password, Validators.required],
|
||||
reason: this.digitalSignature.reason,
|
||||
base64EncodedPrivateKey: this.digitalSignatureExists
|
||||
? null
|
||||
: [this.digitalSignature.base64EncodedPrivateKey, Validators.required],
|
||||
get currentCertificateType() {
|
||||
if (!this.digitalSignature) {
|
||||
return;
|
||||
}
|
||||
return 'contactInfo' in this.digitalSignature ? DigitalSignatureOptions.PKCS : DigitalSignatureOptions.KMS;
|
||||
}
|
||||
|
||||
get activeComponent() {
|
||||
return this.currentCertificateType === DigitalSignatureOptions.PKCS
|
||||
? this.pkcsSignatureConfigurationComponent
|
||||
: this.kmsSignatureConfigurationComponent;
|
||||
}
|
||||
|
||||
openConfigureCertificate(): void {
|
||||
const dialogRef = this._dialogService.openDialog('configureCertificate', null, null);
|
||||
firstValueFrom(dialogRef.afterClosed()).then(async res => {
|
||||
if (res) {
|
||||
await this.loadDigitalSignature();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async loadDigitalSignature(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
this.digitalSignature = await firstValueFrom(this._digitalSignatureService.getSignature());
|
||||
this._loadingService.stop();
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ import { ActiveDossiersService } from '@services/dossiers/active-dossiers.servic
|
||||
import { UserService } from '@services/user.service';
|
||||
import { IDossierAttributeConfig, IFileAttributeConfig, IReportTemplate } from '@red/domain';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
import { ConfigureCertificateDialogComponent } from '../dialogs/configure-digital-signature-dialog/configure-certificate-dialog.component';
|
||||
|
||||
type DialogType =
|
||||
| 'confirm'
|
||||
@ -42,7 +43,8 @@ type DialogType =
|
||||
| 'addEditDossierAttribute'
|
||||
| 'uploadDictionary'
|
||||
| 'addEditDossierState'
|
||||
| 'deleteDossierState';
|
||||
| 'deleteDossierState'
|
||||
| 'configureCertificate';
|
||||
|
||||
@Injectable()
|
||||
export class AdminDialogService extends DialogService<DialogType> {
|
||||
@ -95,6 +97,10 @@ export class AdminDialogService extends DialogService<DialogType> {
|
||||
deleteDossierState: {
|
||||
component: ConfirmDeleteDossierStateDialogComponent,
|
||||
},
|
||||
configureCertificate: {
|
||||
component: ConfigureCertificateDialogComponent,
|
||||
dialogConfig: { disableClose: false, maxHeight: '100vh' },
|
||||
},
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { GenericService, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { Observable } from 'rxjs';
|
||||
import { IDigitalSignature, IDigitalSignatureRequest } from '@red/domain';
|
||||
import { filterEach, GenericService, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { filter, forkJoin, Observable, of } from 'rxjs';
|
||||
import {
|
||||
IDigitalSignatureRequest,
|
||||
IKmsDigitalSignature,
|
||||
IKmsDigitalSignatureRequest,
|
||||
IPkcsDigitalSignature,
|
||||
IPkcsDigitalSignatureRequest,
|
||||
} from '@red/domain';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class DigitalSignatureService extends GenericService<IDigitalSignatureRequest> {
|
||||
@ -10,20 +17,34 @@ export class DigitalSignatureService extends GenericService<IDigitalSignatureReq
|
||||
}
|
||||
|
||||
@Validate()
|
||||
update(@RequiredParam() body: IDigitalSignatureRequest): Observable<unknown> {
|
||||
updateSignature(@RequiredParam() body: IPkcsDigitalSignatureRequest): Observable<unknown> {
|
||||
return this._put(body);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
save(@RequiredParam() body: IDigitalSignature): Observable<IDigitalSignatureRequest> {
|
||||
saveSignature(@RequiredParam() body: IPkcsDigitalSignature): Observable<IPkcsDigitalSignatureRequest> {
|
||||
return this._post(body);
|
||||
}
|
||||
|
||||
delete(): Observable<unknown> {
|
||||
@Validate()
|
||||
saveKmsSignature(@RequiredParam() body: IKmsDigitalSignature): Observable<IKmsDigitalSignatureRequest> {
|
||||
return this._post(body, `${this._defaultModelPath}/kms`);
|
||||
}
|
||||
|
||||
deleteSignature(): Observable<unknown> {
|
||||
return super.delete({});
|
||||
}
|
||||
|
||||
deleteKmsSignature(): Observable<unknown> {
|
||||
return super.delete({}, `${this._defaultModelPath}/kms`);
|
||||
}
|
||||
|
||||
getSignature(): Observable<IDigitalSignatureRequest> {
|
||||
return super.getAll();
|
||||
const digitalSignature$ = super.getAll().pipe(catchError(() => of(null)));
|
||||
const kmsDigitalSignature$ = super.getAll(`${this._defaultModelPath}/kms`).pipe(catchError(() => of(null)));
|
||||
return forkJoin([digitalSignature$, kmsDigitalSignature$]).pipe(
|
||||
filterEach(signature => !!signature),
|
||||
map(signatures => signatures[0] as IDigitalSignatureRequest),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
export const digitalSignatureDialogTranslations = {
|
||||
title: {
|
||||
beforeConfiguration: _('digital-signature-dialog.title.before-configuration'),
|
||||
pkcs: _('digital-signature-dialog.title.pkcs'),
|
||||
kms: _('digital-signature-dialog.title.kms'),
|
||||
},
|
||||
} as const;
|
||||
@ -3,37 +3,21 @@
|
||||
|
||||
<div class="dialog-content">
|
||||
<div translate="import-redactions-dialog.details" class="mb-24"></div>
|
||||
<div
|
||||
class="upload-area"
|
||||
*ngIf="!fileToImport"
|
||||
(click)="triggerAttachFile()"
|
||||
redactionDragDropFileUpload
|
||||
(fileDropped)="attachFile($event)"
|
||||
>
|
||||
<mat-icon svgIcon="iqser:upload"></mat-icon>
|
||||
<div translate="import-redactions-dialog.upload-area-text"></div>
|
||||
</div>
|
||||
<ng-container *ngIf="fileToImport">
|
||||
<div class="file-area">
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
<p>{{ fileToImport.name }}</p>
|
||||
<mat-icon svgIcon="iqser:trash" (click)="removeFile()"></mat-icon>
|
||||
</div>
|
||||
<div class="only-for-pages">
|
||||
<mat-checkbox
|
||||
(change)="onlyForSpecificPages = !onlyForSpecificPages"
|
||||
[checked]="onlyForSpecificPages"
|
||||
class="filter-menu-checkbox"
|
||||
color="primary"
|
||||
>
|
||||
{{ 'import-redactions-dialog.only-for-specific-pages' | translate }}
|
||||
</mat-checkbox>
|
||||
<iqser-upload-file (fileChanged)="fileChanged($event)"></iqser-upload-file>
|
||||
<div class="only-for-pages" *ngIf="fileToImport">
|
||||
<mat-checkbox
|
||||
(change)="onlyForSpecificPages = !onlyForSpecificPages"
|
||||
[checked]="onlyForSpecificPages"
|
||||
class="filter-menu-checkbox"
|
||||
color="primary"
|
||||
>
|
||||
{{ 'import-redactions-dialog.only-for-specific-pages' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<div *ngIf="onlyForSpecificPages" class="iqser-input-group datepicker-wrapper">
|
||||
<input />
|
||||
</div>
|
||||
<div *ngIf="onlyForSpecificPages" class="iqser-input-group datepicker-wrapper">
|
||||
<input />
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
@ -45,5 +29,3 @@
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
<input #attachFileInput [hidden]="true" (change)="attachFile($event)" class="file-upload-input" type="file" accept="application/pdf" />
|
||||
|
||||
@ -1,62 +1,3 @@
|
||||
@use 'variables';
|
||||
|
||||
.upload-area,
|
||||
.file-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
width: 586px;
|
||||
background: variables.$grey-2;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
gap: 16px;
|
||||
height: 88px;
|
||||
cursor: pointer;
|
||||
|
||||
mat-icon,
|
||||
div {
|
||||
opacity: 0.5;
|
||||
transition: 0.1s;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
div {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.file-area {
|
||||
gap: 10px;
|
||||
height: 48px;
|
||||
|
||||
mat-icon:first-child {
|
||||
opacity: 0.5;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
mat-icon:last-child {
|
||||
margin-left: auto;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
transform: scale(0.7);
|
||||
}
|
||||
|
||||
p {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
max-width: 490px;
|
||||
}
|
||||
}
|
||||
|
||||
.only-for-pages {
|
||||
margin-top: 16px;
|
||||
margin-left: 21px;
|
||||
|
||||
@ -33,28 +33,13 @@ export class ImportRedactionsDialogComponent extends BaseDialogComponent {
|
||||
super(_injector, _dialogRef);
|
||||
}
|
||||
|
||||
triggerAttachFile() {
|
||||
this.attachFileInput.nativeElement.click();
|
||||
}
|
||||
|
||||
attachFile(event) {
|
||||
const files = event.target['files'];
|
||||
this.fileToImport = files[0];
|
||||
|
||||
// input field needs to be set as empty in case the same file will be selected second time
|
||||
event.target.value = '';
|
||||
|
||||
fileChanged(file: File | null) {
|
||||
this.fileToImport = file;
|
||||
if (!this.fileToImport) {
|
||||
console.error('No file to import!');
|
||||
return;
|
||||
this.onlyForSpecificPages = false;
|
||||
}
|
||||
}
|
||||
|
||||
removeFile() {
|
||||
this.fileToImport = null;
|
||||
this.onlyForSpecificPages = false;
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const import$ = this._redactionImportService.importRedactions(this.data.dossierId, this.data.fileId, this.fileToImport);
|
||||
|
||||
@ -24,14 +24,6 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.fields-container {
|
||||
flex-direction: column;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
redaction-small-chip {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
import { Directive, EventEmitter, Output, HostListener, HostBinding } from '@angular/core';
|
||||
|
||||
const DRAG_OVER_BACKGROUND_COLOR = '#e2eefd';
|
||||
const DEFAULT_BACKGROUND_COLOR = '#f4f5f7';
|
||||
|
||||
@Directive({
|
||||
selector: '[redactionDragDropFileUpload]',
|
||||
})
|
||||
export class DragDropFileUploadDirective {
|
||||
@Output() readonly fileDropped = new EventEmitter<any>();
|
||||
@HostBinding('style.background-color') private background = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
@HostListener('dragover', ['$event'])
|
||||
onDragOver(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.dataTransfer.types.includes('Files')) {
|
||||
this.background = DRAG_OVER_BACKGROUND_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('dragleave', ['$event'])
|
||||
onDragLeave(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.background = DEFAULT_BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
@HostListener('drop', ['$event'])
|
||||
onDrop(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.dataTransfer.types.includes('Files')) {
|
||||
this.background = DEFAULT_BACKGROUND_COLOR;
|
||||
const files = event.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
this.fileDropped.emit({ target: { files } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,6 @@ import { FileStatsComponent } from './components/file-stats/file-stats.component
|
||||
import { FileNameColumnComponent } from '@shared/components/file-name-column/file-name-column.component';
|
||||
import { DossierNameColumnComponent } from '@shared/components/dossier-name-column/dossier-name-column.component';
|
||||
import { MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { DragDropFileUploadDirective } from '@shared/directives/drag-drop-file-upload.directive';
|
||||
import { DossiersTypeSwitchComponent } from '@shared/components/dossiers-type-switch/dossiers-type-switch.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
@ -62,7 +61,7 @@ const components = [
|
||||
...buttons,
|
||||
];
|
||||
|
||||
const utils = [DatePipe, NamePipe, NavigateLastDossiersScreenDirective, LongPressDirective, DragDropFileUploadDirective];
|
||||
const utils = [DatePipe, NamePipe, NavigateLastDossiersScreenDirective, LongPressDirective];
|
||||
|
||||
const services = [SharedDialogService];
|
||||
|
||||
|
||||
@ -648,40 +648,64 @@
|
||||
}
|
||||
},
|
||||
"digital-signature": "Digitale Signatur",
|
||||
"digital-signature-dialog": {
|
||||
"actions": {
|
||||
"back": "",
|
||||
"cancel": "",
|
||||
"certificate-not-valid-error": "",
|
||||
"continue": "",
|
||||
"save": "",
|
||||
"save-error": "",
|
||||
"save-success": ""
|
||||
},
|
||||
"forms": {
|
||||
"kms": {
|
||||
"certificate-content": "",
|
||||
"certificate-name": "",
|
||||
"kms-access-key": "",
|
||||
"kms-id": "",
|
||||
"kms-region": "",
|
||||
"kms-secret-key": "",
|
||||
"kms-service-endpoint": ""
|
||||
},
|
||||
"pkcs": {
|
||||
"certificate-name": "",
|
||||
"contact-information": "",
|
||||
"location": "",
|
||||
"password-key": "",
|
||||
"reason": ""
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"kms": {
|
||||
"description": "",
|
||||
"label": ""
|
||||
},
|
||||
"pkcs": {
|
||||
"description": "",
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"before-configuration": "",
|
||||
"kms": "",
|
||||
"pkcs": ""
|
||||
},
|
||||
"upload-warning-message": ""
|
||||
},
|
||||
"digital-signature-screen": {
|
||||
"action": {
|
||||
"certificate-not-valid-error": "Das hochgeladene Zertifikat eignet sich nicht zum Signieren von PDF-Dokumenten. Sie benötigen das Format PCKS#12.",
|
||||
"delete": "Digitale Signatur löschen",
|
||||
"certificate-not-valid-error": "",
|
||||
"delete-error": "Die digitale Signatur konnte nicht entfernt werden, bitte versuchen Sie es erneut.",
|
||||
"delete-success": "Die digitale Signatur wurde gelöscht. Geschwärzte Dateien werden nicht länger mit einer Signatur versehen!",
|
||||
"reset": "Zurücksetzen",
|
||||
"remove": "",
|
||||
"save": "Digitale Signatur speichern",
|
||||
"save-error": "Fehler beim Speichern der digitalen Signatur",
|
||||
"save-success": "Digitale Signatur erfolgreich gespeichert"
|
||||
},
|
||||
"certificate-name": {
|
||||
"label": "Name des Zertifikats",
|
||||
"placeholder": "Name des Zertifikats"
|
||||
},
|
||||
"contact-info": {
|
||||
"label": "Kontaktdaten",
|
||||
"placeholder": "Kontaktdaten"
|
||||
},
|
||||
"location": {
|
||||
"label": "Ort",
|
||||
"placeholder": "Ort"
|
||||
"save-error": "",
|
||||
"save-success": ""
|
||||
},
|
||||
"no-data": {
|
||||
"action": "Zertifikat hochladen",
|
||||
"title": "Es ist kein Zertifikat für die digitale Signatur konfiguriert. Laden Sie ein PCKS#12-Zertifikat hoch, um Ihre geschwärzten Dokumente zu signieren."
|
||||
},
|
||||
"password": {
|
||||
"label": "Zertifikatspasswort/-schlüssel",
|
||||
"placeholder": "Passwort"
|
||||
},
|
||||
"reason": {
|
||||
"label": "Begründung",
|
||||
"placeholder": "Begründung"
|
||||
}
|
||||
},
|
||||
"document-info": {
|
||||
|
||||
@ -648,40 +648,63 @@
|
||||
}
|
||||
},
|
||||
"digital-signature": "Digital Signature",
|
||||
"digital-signature-dialog": {
|
||||
"actions": {
|
||||
"back": "Back",
|
||||
"cancel": "Cancel",
|
||||
"certificate-not-valid-error": "Uploaded Certificate is not valid!",
|
||||
"continue": "Continue",
|
||||
"save": "Save Configurations",
|
||||
"save-error": "Failed to save digital signature!",
|
||||
"save-success": "Digital Signature Certificate successfully saved!"
|
||||
},
|
||||
"forms": {
|
||||
"kms": {
|
||||
"certificate-content": "Certificate Content",
|
||||
"certificate-name": "Certificate Name",
|
||||
"kms-access-key": "KMS Access Key",
|
||||
"kms-id": "KMS Id",
|
||||
"kms-region": "KMS Region",
|
||||
"kms-secret-key": "KMS Secret Key",
|
||||
"kms-service-endpoint": "KMS Service Endpoint"
|
||||
},
|
||||
"pkcs": {
|
||||
"certificate-name": "Certificate Name",
|
||||
"contact-information": "Contact Information",
|
||||
"location": "Location",
|
||||
"password-key": "Password Key",
|
||||
"reason": "Reason"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"kms": {
|
||||
"description": "Provide a corresponding PEM file containing the certificate, along with Amazon KMS credentials needed for securing the private key.",
|
||||
"label": "I use an Amazon KMS private key"
|
||||
},
|
||||
"pkcs": {
|
||||
"description": "A PKCS#12 file is a file that bundles the private key and the X.509 certificate. The password protection is required to secure the private key. Unprotected PKCS#12 files are not supported.",
|
||||
"label": "I want to upload a PKCS#12 file"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"before-configuration": "Configure Digital Signature Certificate",
|
||||
"kms": "Configure a Certificate with Amazon KMS",
|
||||
"pkcs": "Configure a PKCS#12 Certificate"
|
||||
},
|
||||
"upload-warning-message": "To configure the certificate, you first need to upload it."
|
||||
},
|
||||
"digital-signature-screen": {
|
||||
"action": {
|
||||
"certificate-not-valid-error": "Uploaded Certificate is not valid for signing PDFs. PCKS.12 format is required.",
|
||||
"delete": "Delete Digital Signature",
|
||||
"delete-error": "Failed to remove digital signature, please try again.",
|
||||
"delete-success": "Digital signature removed. Redacted files will no longer be signed!",
|
||||
"reset": "Reset",
|
||||
"save": "Save Digital Signature",
|
||||
"save-error": "Failed to save digital signature",
|
||||
"save-success": "Digital signature saved successfully"
|
||||
},
|
||||
"certificate-name": {
|
||||
"label": "Certificate Name",
|
||||
"placeholder": "Certificate Name"
|
||||
},
|
||||
"contact-info": {
|
||||
"label": "Contact Information",
|
||||
"placeholder": "Contact Information"
|
||||
},
|
||||
"location": {
|
||||
"label": "Location",
|
||||
"placeholder": "Location"
|
||||
"remove": "Remove",
|
||||
"save": "Save Changes",
|
||||
"save-error": "Failed to save digital signature!",
|
||||
"save-success": "Digital Signature Certificate successfully saved!"
|
||||
},
|
||||
"no-data": {
|
||||
"action": "Upload Certificate",
|
||||
"title": "No Digital Signature certificate is configured. For signing redacted documents please upload a PCKS.12 certificate."
|
||||
},
|
||||
"password": {
|
||||
"label": "Certificate Password/Key",
|
||||
"placeholder": "Password"
|
||||
},
|
||||
"reason": {
|
||||
"label": "Reason",
|
||||
"placeholder": "Reason"
|
||||
"action": "Configure Certificate",
|
||||
"title": "No Digital Signature Certificate.<br/>For signing redacted documents please configure a certificate."
|
||||
}
|
||||
},
|
||||
"document-info": {
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit a814fc8aa7a16c9acdaa9b7dd749e4493a54e1c2
|
||||
Subproject commit e5542086ddd2e1548276d47d36161c89179d64e4
|
||||
@ -25,3 +25,4 @@ export * from './lib/trash';
|
||||
export * from './lib/text-highlight';
|
||||
export * from './lib/permissions';
|
||||
export * from './lib/license';
|
||||
export * from './lib/digital-signature';
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
export const DigitalSignatureOptions = {
|
||||
KMS: 'KMS',
|
||||
PKCS: 'PKCS',
|
||||
} as const;
|
||||
|
||||
export type DigitalSignatureOption = keyof typeof DigitalSignatureOptions;
|
||||
1
libs/red-domain/src/lib/digital-signature/index.ts
Normal file
1
libs/red-domain/src/lib/digital-signature/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './digital-signature-options';
|
||||
@ -1,6 +1,3 @@
|
||||
export interface IDigitalSignatureRequest {
|
||||
certificateName?: string;
|
||||
contactInfo?: string;
|
||||
location?: string;
|
||||
reason?: string;
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
import { IDigitalSignatureRequest } from './digital-signature.request';
|
||||
|
||||
export interface IDigitalSignature extends IDigitalSignatureRequest {
|
||||
base64EncodedPrivateKey?: string;
|
||||
password?: string;
|
||||
}
|
||||
@ -1,2 +1,5 @@
|
||||
export * from './digital-signature.request';
|
||||
export * from './digital-signature';
|
||||
export * from './pkcs-digital-signature.request';
|
||||
export * from './kms-digital-signature.request';
|
||||
export * from './pkcs-digital-signature';
|
||||
export * from './kms-digital-signature';
|
||||
export * from './digital-signature-request';
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { IDigitalSignatureRequest } from './digital-signature-request';
|
||||
|
||||
export interface IKmsDigitalSignatureRequest extends IDigitalSignatureRequest {
|
||||
kmsAccessKey?: string;
|
||||
kmsKeyId?: string;
|
||||
kmsRegion?: string;
|
||||
kmsServiceEndpoint?: string;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { IKmsDigitalSignatureRequest } from './kms-digital-signature.request';
|
||||
|
||||
export interface IKmsDigitalSignature extends IKmsDigitalSignatureRequest {
|
||||
certificate?: string;
|
||||
kmsSecretKey?: string;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
import { IDigitalSignatureRequest } from './digital-signature-request';
|
||||
|
||||
export interface IPkcsDigitalSignatureRequest extends IDigitalSignatureRequest {
|
||||
contactInfo?: string;
|
||||
location?: string;
|
||||
reason?: string;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { IPkcsDigitalSignatureRequest } from './pkcs-digital-signature.request';
|
||||
|
||||
export interface IPkcsDigitalSignature extends IPkcsDigitalSignatureRequest {
|
||||
base64EncodedPrivateKey?: string;
|
||||
password?: string;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user