red-ui/apps/red-ui/src/app/models/file/file-data.model.ts
2021-06-07 15:13:31 +03:00

265 lines
11 KiB
TypeScript

import {
IdRemoval,
ManualRedactionEntry,
ManualRedactions,
RedactionChangeLog,
RedactionLog,
ViewedPages
} from '@redaction/red-ui-http';
import { FileStatusWrapper } from './file-status.wrapper';
import { UserWrapper } from '@services/user.service';
import { AnnotationWrapper } from './annotation.wrapper';
import { RedactionLogEntryWrapper } from './redaction-log-entry.wrapper';
import { ViewMode } from './view-mode';
import { TypeValueWrapper } from './type-value.wrapper';
export class AnnotationData {
visibleAnnotations: AnnotationWrapper[];
allAnnotations: AnnotationWrapper[];
}
export class FileDataModel {
constructor(
public fileStatus: FileStatusWrapper,
public fileData: Blob,
public redactionLog: RedactionLog,
public redactionChangeLog: RedactionChangeLog,
public manualRedactions: ManualRedactions,
public viewedPages?: ViewedPages
) {}
getAnnotations(
dictionaryData: { [p: string]: TypeValueWrapper },
currentUser: UserWrapper,
viewMode: ViewMode,
areDevFeaturesEnabled: boolean
): AnnotationData {
const entries: RedactionLogEntryWrapper[] = this._convertData(dictionaryData);
let allAnnotations = entries.map(entry => AnnotationWrapper.fromData(entry));
if (!areDevFeaturesEnabled) {
allAnnotations = allAnnotations.filter(annotation => !annotation.isFalsePositive);
}
const visibleAnnotations = allAnnotations.filter(annotation => {
if (viewMode === 'STANDARD') {
return !annotation.isChangeLogRemoved;
} else if (viewMode === 'DELTA') {
return annotation.isChangeLogEntry;
} else {
return annotation.isRedacted;
}
});
return {
visibleAnnotations: visibleAnnotations,
allAnnotations: allAnnotations
};
}
private _convertData(dictionaryData: {
[p: string]: TypeValueWrapper;
}): RedactionLogEntryWrapper[] {
let result: RedactionLogEntryWrapper[] = [];
this.redactionChangeLog?.redactionLogEntry?.forEach(changeLogEntry => {
if (changeLogEntry.changeType === 'REMOVED') {
// Fix backend issue where some annotations are both added and removed
const sameEntryExistsAsAdd = !!this.redactionChangeLog.redactionLogEntry.find(
rle => rle.id === changeLogEntry.id && rle.changeType === 'ADDED'
);
if (sameEntryExistsAsAdd) {
return;
}
const redactionLogEntryWrapper: RedactionLogEntryWrapper = {
actionPendingReanalysis: false
};
Object.assign(redactionLogEntryWrapper, changeLogEntry);
redactionLogEntryWrapper.comments =
this.manualRedactions.comments[redactionLogEntryWrapper.id];
redactionLogEntryWrapper.isChangeLogEntry = true;
redactionLogEntryWrapper.changeLogType = changeLogEntry.changeType;
redactionLogEntryWrapper.id = 'changed-log-removed-' + redactionLogEntryWrapper.id;
result.push(redactionLogEntryWrapper);
}
});
this.redactionLog.redactionLogEntry?.forEach(redactionLogEntry => {
// false positive entries from the redaction-log need to be skipped
if (redactionLogEntry.type?.toLowerCase() === 'false_positive') {
return;
}
const existingChangeLogEntry = this.redactionChangeLog?.redactionLogEntry?.find(
rle => rle.id === redactionLogEntry.id
);
// copy the redactionLog Entry
const redactionLogEntryWrapper: RedactionLogEntryWrapper = {
actionPendingReanalysis: false
};
Object.assign(redactionLogEntryWrapper, redactionLogEntry);
redactionLogEntryWrapper.comments =
this.manualRedactions.comments[redactionLogEntryWrapper.id];
redactionLogEntryWrapper.isChangeLogEntry = !!existingChangeLogEntry;
redactionLogEntryWrapper.changeLogType = 'ADDED';
result.push(redactionLogEntryWrapper);
});
this.manualRedactions.forceRedactions?.forEach(forceRedaction => {
const relevantRedactionLogEntry = result.find(r => r.id === forceRedaction.id);
if (forceRedaction.status === 'DECLINED') {
relevantRedactionLogEntry.status = 'DECLINED';
relevantRedactionLogEntry.userId = forceRedaction.user;
relevantRedactionLogEntry.dictionaryEntry = false;
relevantRedactionLogEntry.force = true;
return;
}
// an entry for this request already exists in the redactionLog
if (relevantRedactionLogEntry) {
relevantRedactionLogEntry.userId = forceRedaction.user;
relevantRedactionLogEntry.dictionaryEntry = false;
relevantRedactionLogEntry.force = true;
// if statuses differ
if (
!forceRedaction.processedDate ||
forceRedaction.status !== relevantRedactionLogEntry.status
) {
relevantRedactionLogEntry.actionPendingReanalysis = true;
relevantRedactionLogEntry.status = forceRedaction.status;
}
}
});
this.manualRedactions.entriesToAdd?.forEach(manual => {
const markedAsReasonRedactionLogEntry = result.find(r => r.id === manual.reason);
const relevantRedactionLogEntry = result.find(r => r.id === manual.id);
// a redaction-log entry is marked as a reason for another entry - hide it
if (markedAsReasonRedactionLogEntry) {
if (!(this._hasAlreadyBeenProcessed(manual) && manual.status === 'APPROVED')) {
markedAsReasonRedactionLogEntry.hidden = true;
}
}
// an entry for this request already exists in the redactionLog
if (relevantRedactionLogEntry) {
if (relevantRedactionLogEntry.status === 'DECLINED') {
relevantRedactionLogEntry.hidden = true;
return;
}
relevantRedactionLogEntry.userId = manual.user;
relevantRedactionLogEntry.dictionaryEntry = manual.addToDictionary;
// if statuses differ
if (relevantRedactionLogEntry.status !== manual.status) {
relevantRedactionLogEntry.actionPendingReanalysis = true;
relevantRedactionLogEntry.status = manual.status;
}
} else {
// dictionary modifying requests that have been processed already updated
// the dictionary and should not be drawn
if (manual.addToDictionary && this._hasAlreadyBeenProcessed(manual)) {
return;
}
// no entry exists in the redaction log - create it
const dictionary = dictionaryData[manual.type];
const redactionLogEntryWrapper: RedactionLogEntryWrapper = {};
redactionLogEntryWrapper.id = manual.id;
redactionLogEntryWrapper.dictionaryEntry = manual.addToDictionary;
redactionLogEntryWrapper.legalBasis = manual.legalBasis;
redactionLogEntryWrapper.positions = manual.positions;
redactionLogEntryWrapper.reason = manual.reason;
redactionLogEntryWrapper.status = manual.status;
redactionLogEntryWrapper.type = manual.type;
redactionLogEntryWrapper.userId = manual.user;
redactionLogEntryWrapper.value = manual.value;
redactionLogEntryWrapper.redacted = !dictionary.hint;
redactionLogEntryWrapper.hint = dictionary.hint;
redactionLogEntryWrapper.manualRedactionType = 'ADD';
redactionLogEntryWrapper.manual = true;
redactionLogEntryWrapper.comments =
this.manualRedactions.comments[redactionLogEntryWrapper.id];
if (markedAsReasonRedactionLogEntry) {
// cleanup reason if the reason is another annotationId
// it is not needed for drawing
redactionLogEntryWrapper.reason = null;
}
result.push(redactionLogEntryWrapper);
}
});
this.manualRedactions.idsToRemove?.forEach(idToRemove => {
const relevantRedactionLogEntry = result.find(r => r.id === idToRemove.id);
if (!relevantRedactionLogEntry) {
// idRemove for something that doesn't exist - skip
return;
} else {
relevantRedactionLogEntry.userId = idToRemove.user;
relevantRedactionLogEntry.dictionaryEntry = idToRemove.removeFromDictionary;
// if statuses differ
if (relevantRedactionLogEntry.status !== idToRemove.status) {
relevantRedactionLogEntry.actionPendingReanalysis = true;
relevantRedactionLogEntry.status = idToRemove.status;
}
if (this._hasAlreadyBeenProcessed(idToRemove)) {
if (idToRemove.status === 'DECLINED') {
relevantRedactionLogEntry.status = null;
}
}
}
});
result.forEach(redactionLogEntry => {
if (redactionLogEntry.manual) {
if (redactionLogEntry.manualRedactionType === 'ADD') {
const foundManualEntry = this.manualRedactions.entriesToAdd.find(
me => me.id === redactionLogEntry.id
);
// ADD has been undone - not yet processed
if (!foundManualEntry) {
redactionLogEntry.hidden = true;
}
}
if (redactionLogEntry.manualRedactionType === 'REMOVE') {
const foundManualEntry = this.manualRedactions.idsToRemove.find(
me => me.id === redactionLogEntry.id
);
// REMOVE has been undone - not yet processed
if (!foundManualEntry) {
redactionLogEntry.manual = false;
redactionLogEntry.manualRedactionType = 'UNDO';
redactionLogEntry.status = null;
}
}
}
});
// remove undone entriesToAdd and idsToRemove
result = result.filter(redactionLogEntry => !redactionLogEntry.hidden);
return result;
}
private _hasAlreadyBeenProcessed(entry: ManualRedactionEntry | IdRemoval): boolean {
return !entry.processedDate
? false
: new Date(entry.processedDate).getTime() <
new Date(this.fileStatus.lastProcessed).getTime();
}
}