From 929aa355d7cf7977bf4f3500bea78763f0fd070a Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Tue, 17 Aug 2021 21:21:42 +0300 Subject: [PATCH] excluded pages fix and legal basis / image reacat fix --- .../src/app/models/file/annotation.wrapper.ts | 40 ++++++++++++------- .../watermark/watermark-screen.component.ts | 2 +- .../file-workload.component.html | 6 +-- .../page-exclusion.component.ts | 39 +++++++++--------- .../type-annotation-icon.component.ts | 4 +- .../recategorize-image-dialog.component.ts | 4 +- .../remove-annotations-dialog.component.html | 2 +- .../remove-annotations-dialog.component.ts | 2 +- .../dossier-overview-screen.component.html | 2 - .../dossier-overview-screen.component.ts | 2 +- .../file-preview-screen.component.ts | 36 +++++++++-------- .../services/annotation-draw.service.ts | 4 +- .../services/annotation-processing.service.ts | 8 ++-- .../services/manual-annotation.service.ts | 2 +- .../dossier/utils/compare-mode.utils.ts | 12 +----- apps/red-ui/src/app/utils/page-stamper.ts | 26 ++++++++++-- 16 files changed, 106 insertions(+), 85 deletions(-) diff --git a/apps/red-ui/src/app/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index eb4d1d267..378755fad 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -26,7 +26,8 @@ export type AnnotationSuperType = export class AnnotationWrapper { superType: AnnotationSuperType; - dictionary: string; + typeValue: string; + recategorizationType: string; color: string; comments: Comment[] = []; firstTopLeftPoint: Point; @@ -42,7 +43,7 @@ export class AnnotationWrapper { dictionaryOperation: boolean; positions: Rectangle[]; recommendationType: string; - legalBasis: string; + legalBasisValue: string; legalBasisChangeValue?: string; manual?: boolean; @@ -89,11 +90,15 @@ export class AnnotationWrapper { } get isImage() { - return this.dictionary?.toLowerCase() === 'image' || this.image; + return this.type?.toLowerCase() === 'image' || this.image; } get isOCR() { - return this.dictionary?.toLowerCase() === 'ocr'; + return this.type?.toLowerCase() === 'ocr'; + } + + get type() { + return this.recategorizationType || this.typeValue; } get isManuallySkipped() { @@ -102,7 +107,7 @@ export class AnnotationWrapper { get isFalsePositive() { return ( - this.dictionary?.toLowerCase() === 'false_positive' && + this.type?.toLowerCase() === 'false_positive' && (this.superType === 'skipped' || this.superType === 'hint' || this.superType === 'redaction') ); } @@ -185,6 +190,10 @@ export class AnnotationWrapper { return this.firstTopLeftPoint.y; } + get legalBasis() { + return this.legalBasisChangeValue || this.legalBasisValue; + } + static fromData(redactionLogEntry?: RedactionLogEntryWrapper) { const annotationWrapper = new AnnotationWrapper(); @@ -195,7 +204,8 @@ export class AnnotationWrapper { annotationWrapper.changeLogType = redactionLogEntry.changeLogType; annotationWrapper.redaction = redactionLogEntry.redacted; annotationWrapper.hint = redactionLogEntry.hint; - annotationWrapper.dictionary = redactionLogEntry.type; + annotationWrapper.typeValue = redactionLogEntry.type; + annotationWrapper.recategorizationType = redactionLogEntry.recategorizationType; annotationWrapper.value = redactionLogEntry.value; annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; @@ -206,8 +216,8 @@ export class AnnotationWrapper { annotationWrapper.dictionaryOperation = redactionLogEntry.dictionaryEntry; annotationWrapper.image = redactionLogEntry.image; annotationWrapper.legalBasisChangeValue = redactionLogEntry.legalBasisChangeValue; + annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis; annotationWrapper.comments = redactionLogEntry.comments || []; - annotationWrapper.legalBasis = redactionLogEntry.legalBasis; annotationWrapper.manual = redactionLogEntry.manual; this._createContent(annotationWrapper, redactionLogEntry); @@ -247,7 +257,7 @@ export class AnnotationWrapper { return; } - if (annotationWrapper.dictionary?.toLowerCase() === 'false_positive') { + if (annotationWrapper.type?.toLowerCase() === 'false_positive') { if (redactionLogEntryWrapper.status === 'REQUESTED') { annotationWrapper.superType = 'suggestion-add-dictionary'; return; @@ -372,24 +382,24 @@ export class AnnotationWrapper { content += entry.reason + '\n\n'; } - if (entry.legalBasisChangeValue || entry.legalBasis) { - content += 'Legal basis: ' + entry.legalBasis + '\n\n'; + if (annotationWrapper.legalBasis) { + content += 'Legal basis: ' + annotationWrapper.legalBasis + '\n\n'; } if (entry.section) { content += 'In section: "' + entry.section + '"'; } - annotationWrapper.shortContent = this._getShortContent(entry) || content; + annotationWrapper.shortContent = this._getShortContent(annotationWrapper, entry) || content; annotationWrapper.content = content; } - private static _getShortContent(entry: RedactionLogEntryWrapper) { - if (entry.legalBasis) { - const lb = entry.legalBasisMapping?.find(lbm => lbm.reason.toLowerCase().includes(entry.legalBasis.toLowerCase())); + private static _getShortContent(annotationWrapper: AnnotationWrapper, entry: RedactionLogEntryWrapper) { + if (annotationWrapper.legalBasis) { + const lb = entry.legalBasisMapping?.find(lbm => lbm.reason.toLowerCase().includes(annotationWrapper.legalBasis.toLowerCase())); if (lb) return lb.name; } - return entry.legalBasis; + return annotationWrapper.legalBasis; } } diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen.component.ts index 4c333d833..cf2bada3b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen.component.ts @@ -171,7 +171,7 @@ export class WatermarkScreenComponent implements OnInit { const opacity = this.configForm.get('opacity').value; const color = this.configForm.get('hexColor').value; - await stampPDFPage(document, pdfNet, text, fontSize, fontType, orientation, opacity, color, 1); + await stampPDFPage(document, pdfNet, text, fontSize, fontType, orientation, opacity, color, [1]); this._instance.docViewer.refreshAll(); this._instance.docViewer.updateView([0], 0); this._changeDetectorRef.detectChanges(); diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html index 969d3c308..74d473a9f 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html @@ -180,11 +180,11 @@
{{ annotation.typeLabel | translate }}
-
+
{{ annotation.descriptor | translate }}: {{ annotation.dictionary | humanize: false }} + >{{ annotation.type | humanize: false }}
: {{ annotation.shortContent }} @@ -225,7 +225,7 @@
diff --git a/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts b/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts index 991fd9b77..32d0b4ac0 100644 --- a/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts @@ -6,6 +6,7 @@ import { FileDataModel } from '../../../../models/file/file-data.model'; import { Toaster } from '@services/toaster.service'; import { LoadingService } from '@services/loading.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { FileStatusWrapper } from '../../../../models/file/file-status.wrapper'; @Component({ selector: 'redaction-page-exclusion', @@ -13,7 +14,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; styleUrls: ['./page-exclusion.component.scss'] }) export class PageExclusionComponent implements OnChanges { - @Input() fileData: FileDataModel; + @Input() fileStatus: FileStatusWrapper; @Output() actionPerformed = new EventEmitter(); excludePagesForm: FormGroup; @@ -31,22 +32,20 @@ export class PageExclusionComponent implements OnChanges { }); } - ngOnChanges(changes: SimpleChanges) { - if (changes.fileData) { - const excludedPages = (this.fileData?.fileStatus?.excludedPages || []).sort((p1, p2) => p1 - p2); - this.excludedPagesRanges = excludedPages.reduce((ranges, page) => { - if (!ranges.length) { - return [{ startPage: page, endPage: page }]; - } + ngOnChanges() { + const excludedPages = (this.fileStatus?.excludedPages || []).sort((p1, p2) => p1 - p2); + this.excludedPagesRanges = excludedPages.reduce((ranges, page) => { + if (!ranges.length) { + return [{ startPage: page, endPage: page }]; + } - if (page === ranges[ranges.length - 1].endPage + 1) { - ranges[ranges.length - 1].endPage = page; - } else { - ranges.push({ startPage: page, endPage: page }); - } - return ranges; - }, []); - } + if (page === ranges[ranges.length - 1].endPage + 1) { + ranges[ranges.length - 1].endPage = page; + } else { + ranges.push({ startPage: page, endPage: page }); + } + return ranges; + }, []); } async excludePagesRange() { @@ -72,8 +71,8 @@ export class PageExclusionComponent implements OnChanges { { pageRanges: pageRanges }, - this.fileData.fileStatus.dossierId, - this.fileData.fileStatus.fileId + this.fileStatus.dossierId, + this.fileStatus.fileId ) .toPromise(); this.excludePagesForm.reset(); @@ -91,8 +90,8 @@ export class PageExclusionComponent implements OnChanges { { pageRanges: [range] }, - this.fileData.fileStatus.dossierId, - this.fileData.fileStatus.fileId + this.fileStatus.dossierId, + this.fileStatus.fileId ) .toPromise(); this.excludePagesForm.reset(); diff --git a/apps/red-ui/src/app/modules/dossier/components/type-annotation-icon/type-annotation-icon.component.ts b/apps/red-ui/src/app/modules/dossier/components/type-annotation-icon/type-annotation-icon.component.ts index 7a3f36068..9586951ad 100644 --- a/apps/red-ui/src/app/modules/dossier/components/type-annotation-icon/type-annotation-icon.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/type-annotation-icon/type-annotation-icon.component.ts @@ -21,7 +21,7 @@ export class TypeAnnotationIconComponent implements OnChanges { if (this.annotation.isSuperTypeBasedColor) { this.color = this._appStateService.getDictionaryColor(this.annotation.superType); } else { - this.color = this._appStateService.getDictionaryColor(this.annotation.dictionary); + this.color = this._appStateService.getDictionaryColor(this.annotation.type); } this.type = this.annotation.isSuggestion || this.annotation.isDeclinedSuggestion @@ -38,7 +38,7 @@ export class TypeAnnotationIconComponent implements OnChanges { ? 'S' : this.annotation.isReadyForAnalysis ? 'A' - : this.annotation.dictionary[0].toUpperCase(); + : this.annotation.type[0].toUpperCase(); } } } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts index f6ba498c7..da652f537 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts @@ -25,14 +25,14 @@ export class RecategorizeImageDialogComponent implements OnInit { ) {} get changed(): boolean { - return this.recategorizeImageForm.get('type').value !== this.annotations[0].dictionary; + return this.recategorizeImageForm.get('type').value !== this.annotations[0].type; } async ngOnInit() { this.isDocumentAdmin = this._permissionsService.isApprover(); this.recategorizeImageForm = this._formBuilder.group({ - type: [this.annotations[0].dictionary, Validators.required], + type: [this.annotations[0].type, Validators.required], comment: this.isDocumentAdmin ? [null] : [null, Validators.required] }); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.html index 551cdefb5..8c6ccf153 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.html @@ -26,7 +26,7 @@ - {{ annotation.dictionary }} + {{ annotation.type }} {{ annotation.value }} diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.ts index 2a9966164..1a8cbd30b 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/remove-annotations-dialog/remove-annotations-dialog.component.ts @@ -42,7 +42,7 @@ export class RemoveAnnotationsDialogComponent { printable(annotation: AnnotationWrapper) { if (annotation.isImage) { return this._translateService.instant('remove-annotations-dialog.image-type', { - typeLabel: humanize(annotation.dictionary) + typeLabel: humanize(annotation.type) }); } else { return annotation.value; diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html index a0a6532c4..87b67b71c 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html @@ -5,7 +5,6 @@ [showCloseButton]="true" > 0) { + const document = await this._instance.docViewer.getDocument().getPDFDoc(); + await clearStamps(document, this._instance.PDFNet, [...Array(this.fileData.fileStatus.numberOfPages).keys()]); + await stampPDFPage( + document, + this._instance.PDFNet, + this._translateService.instant('file-preview.excluded-from-redaction'), + 25, + 'courier', + 'DIAGONAL', + 33, + '#283241', + excludedPages + ); + } } private async _stampExcludedPages() { - for (const page of this.fileData.fileStatus.excludedPages) { - await this._stampPage(page); - } + await this._doStampExcludedPages(this.fileData.fileStatus.excludedPages); this._instance.docViewer.refreshAll(); this._instance.docViewer.updateView([this.activeViewerPage], this.activeViewerPage); this._changeDetectorRef.detectChanges(); diff --git a/apps/red-ui/src/app/modules/dossier/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-draw.service.ts index 41b9d9b9c..6d0b3ac57 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-draw.service.ts @@ -84,7 +84,7 @@ export class AnnotationDrawService { const pageNumber = compareMode ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber; const highlight = new activeViewer.Annotations.TextHighlightAnnotation(); highlight.PageNumber = pageNumber; - highlight.StrokeColor = this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.dictionary); + highlight.StrokeColor = this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.type); highlight.setContents(annotationWrapper.content); highlight.Quads = this._rectanglesToQuads(annotationWrapper.positions, activeViewer, pageNumber); highlight.Id = annotationWrapper.id; @@ -99,7 +99,7 @@ export class AnnotationDrawService { highlight.setCustomData('changeLog', annotationWrapper.isChangeLogEntry); highlight.setCustomData('changeLogRemoved', annotationWrapper.isChangeLogRemoved); highlight.setCustomData('redactionColor', this.getColor(activeViewer, 'redaction', 'redaction')); - highlight.setCustomData('annotationColor', this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.dictionary)); + highlight.setCustomData('annotationColor', this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.type)); return highlight; } diff --git a/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts index 53a88f38b..0d8f9e6db 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts @@ -37,7 +37,7 @@ export class AnnotationProcessingService { annotations?.forEach(a => { const topLevelFilter = a.superType !== 'hint' && a.superType !== 'redaction' && a.superType !== 'recommendation'; - const key = topLevelFilter ? a.superType : a.superType + a.dictionary; + const key = topLevelFilter ? a.superType : a.superType + a.type; const filter = filterMap.get(key); if (filter) { filter.matches += 1; @@ -51,8 +51,8 @@ export class AnnotationProcessingService { parentFilter = this._createParentFilter(a.superType, filterMap, filters); } const childFilter = { - key: a.dictionary, - label: a.dictionary, + key: a.type, + label: a.type, checked: false, filters: [], matches: 1 @@ -172,7 +172,7 @@ export class AnnotationProcessingService { const superType = annotation.superType; const isNotTopLevelFilter = superType === 'hint' || superType === 'redaction' || superType === 'recommendation'; - return filter.key === superType || (filter.key === annotation.dictionary && isNotTopLevelFilter); + return filter.key === superType || (filter.key === annotation.type && isNotTopLevelFilter); }; private _sortAnnotations(annotations: AnnotationWrapper[]): AnnotationWrapper[] { diff --git a/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts b/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts index da8078b92..8a9462653 100644 --- a/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts @@ -168,7 +168,7 @@ export class ManualAnnotationService { if (this._permissionsService.isApprover()) { // if it was something manual simply decline the existing request - if (annotationWrapper.dictionary === 'manual') { + if (annotationWrapper.type === 'manual') { mode = 'undo'; body = annotationWrapper.id; } else { diff --git a/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts b/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts index f17133c9e..00105b871 100644 --- a/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts +++ b/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts @@ -9,17 +9,9 @@ const processPage = async (pageNumber, document1, document2, mergedDocument, PDF const blankPage = await mergedDocument.pageCreate(await pageToCopy.getCropBox()); await blankPage.setRotation(await pageToCopy.getRotation()); await mergedDocument.pagePushBack(blankPage); - await stampPDFPage( - mergedDocument, - PDFNet, - '<< Compare Placeholder Page >>', - 20, - 'courier', - 'DIAGONAL', - 33, - '#ffb83b', + await stampPDFPage(mergedDocument, PDFNet, '<< Compare Placeholder Page >>', 20, 'courier', 'DIAGONAL', 33, '#ffb83b', [ await mergedDocument.getPageCount() - ); + ]); } }; diff --git a/apps/red-ui/src/app/utils/page-stamper.ts b/apps/red-ui/src/app/utils/page-stamper.ts index 5ee3d14b3..2872b26eb 100644 --- a/apps/red-ui/src/app/utils/page-stamper.ts +++ b/apps/red-ui/src/app/utils/page-stamper.ts @@ -3,6 +3,17 @@ import { environment } from '@environments/environment'; import { PDFNet } from '@pdftron/webviewer'; import PDFDoc = PDFNet.PDFDoc; +export async function clearStamps(document: PDFDoc, PdfNet: any, pages: number[]) { + await PdfNet.runWithCleanup( + async () => { + await document.lock(); + const pageSet = await createPageSet(PdfNet, pages); + await PdfNet.Stamper.deleteStamps(document, pageSet); + }, + environment.licenseKey ? atob(environment.licenseKey) : null + ); +} + export async function stampPDFPage( document: PDFDoc, PdfNet: any, @@ -12,14 +23,13 @@ export async function stampPDFPage( orientation: 'DIAGONAL' | 'HORIZONTAL' | 'VERTICAL', opacity: number, color: string, - page: number + pages: number[] ) { await PdfNet.runWithCleanup( async () => { await document.lock(); - const pageSet = await PdfNet.PageSet.createSinglePage(page); - + const pageSet = await createPageSet(PdfNet, pages); await PdfNet.Stamper.deleteStamps(document, pageSet); const rgbColor = hexToRgb(color); @@ -50,6 +60,16 @@ export async function stampPDFPage( ); } +async function createPageSet(PdfNet: any, pages: number[]) { + const pageSet = await PdfNet.PageSet.create(); + for (const page of pages) { + if (page > 0) { + await pageSet.addPage(page); + } + } + return pageSet; +} + function convertFont(type: string): number { switch (type) { case 'times-new-roman':